获取本机收到的UDP数据包的目标地址

本机收到UDP数据时,通过recvfrom函数可以直接获取发送者的地址:

  1. int recvfrom(  
  2.   __in          SOCKET s,  
  3.   __out         char* buf,  
  4.   __in          int len,  
  5.   __in          int flags,  
  6.   __out         struct sockaddr* from,  
  7.   __in_out      int* fromlen  
  8. );  

但recvfrom没有提供获取包的目标地址的方法,不久前遇到一个需要获取收到包的目标地址的情况,并找到了解决办法。WinSock提供了WSARecvMsg函数来解决类似问题:

  1. int WSARecvMsg(  
  2.   __in          SOCKET s,  
  3.   __in_out      LPWSAMSG lpMsg,  
  4.   __out         LPDWORD lpdwNumberOfBytesRecvd,  
  5.   __in          LPWSAOVERLAPPED lpOverlapped,  
  6.   __in          LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine  
  7. );  

示例代码如下:

  1. #include <WinSock2.h>  
  2. #include <MSWSock.h>  
  3. #include <WS2tcpip.h>  
  4. #include <Windows.h>  
  5. #include <stdio.h>  
  6.   
  7. #pragma comment(lib, "Ws2_32.lib")  
  8.   
  9. int main()  
  10. {  
  11.     WSADATA wd;  
  12.   
  13.     WSAStartup(MAKEWORD(2, 2), &wd);  
  14.   
  15.     SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);  
  16.   
  17.     sockaddr_in sin;  
  18.   
  19.     sin.sin_family = AF_INET;  
  20.     sin.sin_addr.s_addr = INADDR_ANY;  
  21.     sin.sin_port = htons(3333);  
  22.   
  23.     if (SOCKET_ERROR == bind(sock, (sockaddr *)&sin, sizeof(sin)))  
  24.     {  
  25.         closesocket(sock);  
  26.         return 0;  
  27.     }  
  28.   
  29.     int optval = 1;  
  30.     if (SOCKET_ERROR == setsockopt(sock, IPPROTO_IP, IP_PKTINFO, (char*)&optval, sizeof(int)))  
  31.     {  
  32.         closesocket(sock);  
  33.         return 0;  
  34.     }  
  35.   
  36.     GUID guidWSARecvMsg = WSAID_WSARECVMSG;  
  37.     LPFN_WSARECVMSG lpfnWSARecvMsg = NULL;  
  38.     DWORD dwOutSize = 0;  
  39.   
  40.     WSAIoctl(  
  41.         sock,  
  42.         SIO_GET_EXTENSION_FUNCTION_POINTER,  
  43.         &guidWSARecvMsg,  
  44.         sizeof(guidWSARecvMsg),  
  45.         &lpfnWSARecvMsg,  
  46.         sizeof(lpfnWSARecvMsg),  
  47.         &dwOutSize,  
  48.         NULL,  
  49.         NULL  
  50.         );  
  51.   
  52.     if (lpfnWSARecvMsg == NULL)  
  53.     {  
  54.         closesocket(sock);  
  55.         return 0;  
  56.     }  
  57.   
  58.     while (TRUE)  
  59.     {  
  60.         char szControlBuffer[1024] = "";  
  61.         char szDataBuffer[1024] = "";  
  62.         sockaddr_in sin_local;  
  63.         WSABUF wsaBufData;  
  64.         WSAMSG wsaMsg;  
  65.         DWORD dwBytesRecved = 0;  
  66.   
  67.         wsaBufData.buf = szDataBuffer;  
  68.         wsaBufData.len = sizeof(szDataBuffer);  
  69.         wsaMsg.name = (sockaddr *)&sin_local;  
  70.         wsaMsg.namelen = sizeof(sin_local);  
  71.         wsaMsg.lpBuffers = &wsaBufData;  
  72.         wsaMsg.dwBufferCount = 1;  
  73.         wsaMsg.Control.buf = szControlBuffer;  
  74.         wsaMsg.Control.len = sizeof(szControlBuffer);  
  75.         wsaMsg.dwFlags = 0;  
  76.   
  77.         if (0 == lpfnWSARecvMsg(sock, &wsaMsg, &dwBytesRecved, NULL, NULL))  
  78.         {  
  79.             WSACMSGHDR *pCMsgHdr = WSA_CMSG_FIRSTHDR(&wsaMsg);  
  80.   
  81.             if (pCMsgHdr != NULL)  
  82.             {  
  83.                 if (pCMsgHdr->cmsg_type == IP_PKTINFO)  
  84.                 {  
  85.                     IN_PKTINFO *pPktInfo = (IN_PKTINFO *)WSA_CMSG_DATA(pCMsgHdr);  
  86.   
  87.                     if (pPktInfo != NULL)  
  88.                     {  
  89.                         printf(  
  90.                             "%d.%d.%d.%d:%d->%d.%d.%d.%d:%d %s\n",  
  91.                             sin_local.sin_addr.S_un.S_un_b.s_b1,  
  92.                             sin_local.sin_addr.S_un.S_un_b.s_b2,  
  93.                             sin_local.sin_addr.S_un.S_un_b.s_b3,  
  94.                             sin_local.sin_addr.S_un.S_un_b.s_b4,  
  95.                             ntohs(sin_local.sin_port),  
  96.                             pPktInfo->ipi_addr.S_un.S_un_b.s_b1,  
  97.                             pPktInfo->ipi_addr.S_un.S_un_b.s_b2,  
  98.                             pPktInfo->ipi_addr.S_un.S_un_b.s_b3,  
  99.                             pPktInfo->ipi_addr.S_un.S_un_b.s_b4,  
  100.                             3333,  
  101.                             szDataBuffer  
  102.                             );  
  103.                     }  
  104.                 }  
  105.             }  
  106.         }  
  107.         else  
  108.         {  
  109.             break;  
  110.         }  
  111.     }  
  112.   
  113.     closesocket(sock);  
  114.   
  115.     return 0;  
  116. }  

运行效果如下,可以审计到各个本机地址,甚至环回地址也能精确捕获:


WSARecvMsg从Windows2000后都可用,与此对应的WSASendMsg函数却是从vista平台才可以提供的。linux平台中有个recvmsg函数应该可以达到类似的目的。本文中的程序在vs2008中编译通过。


转自:http://blog.csdn.net/my3439955/article/details/8905893

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值