2016-05-19 2 views
2

着信パケットが送信される宛先アドレスの取得に興味があります。 Linux上でたとえば、あなたが利用することができrecvmsgWindows XPのパケットからヘッダーの宛先アドレスを取得する機能

res = recvmsg(socket, &msghdr, 0); 
get_cmsg = CMSG_FIRSTHDR(msghdr); 
struct in_pktinfo *get_pktinfo = (struct in_pktinfo *)CMSG_DATA(get_cmsg); 
printf(" - Header destination address (get_pktinfo.ipi_addr)=%s\n", inet_ntoa(pktinfo.ipi_addr)); 

手順は、ここで重要なrecvmsgは使いやすいということです多くの行数

を節約するためにスキップされました。同様の機能がWindows XPの場合はrecvfromのように実装されていますが、Windowsはrecvmsg機能を実装していないようです。

同様に、WSARevcMsg関数のように、同じ名前の関数が存在しますが、リンクされたドキュメントによれば、それはWindows Vista以上にのみ含まれています。

Windows XPのパケットからヘッダーの宛先アドレスを取得する方法はありますか?


私はこの時点で我々は単にアップグレードできないので、残念ながら我々は、従来の製品にバグを修正しようとしている、XPを使用して悪いと古いであることを知っています。

答えて

2

windowsはrecvmsg機能を実装していないようです。

実際に、それは(も、同等の、とにかく)を行います。

WSARecvMsg function

同様の機能がWSArevcMsgように改良されてきたが、これらは、Windows Vistaおよび上記のみ含まれています。

MSDNのドキュメントを必ずしも信頼できるとは限りません。 MicrosoftがWindows版(XPなど)のサポートを正式に打ち切ると、「最小限のサポート...」などのMSDNからそのバージョンへの参照が削除される傾向にある。多くのプログラマーを悩ますAPI機能の要件。要点はで、をサポートしています。マイクロソフトではをサポートしていません。より古いWindowsバージョン。

WSARecvMsg()は最初、XPで導入された2014年にEOL'edたし、それへの多くの参照MSDNのドキュメントから、被災された(ここでWSARecvMsg()ドキュメントがXPを明記し、Vistaは「最小がサポートされなかった2013年からproofですクライアント ")。 WSARecvFrom()ドキュメントに記載されているように


WSARecvMsg関数の関数ポインタが指定さSIO_GET_EXTENSION_FUNCTION_POINTERオペコードとWSAIoctl()関数の呼び出しを行うことによって、実行時に取得する必要があります。WSAIoctl関数に渡された入力バッファには、​​3210が含まれていなければなりません。この値は、WSARecvMsg拡張機能を識別するグローバル一意識別子(GUID)です。成功すると、WSAIoctl関数によって返された出力には、WSARecvMsg関数へのポインタが含まれます。​​3210 GUIDは、Mswsock.hヘッダーファイルで定義されています。テキスト形式で{F689D7C8-6F1F-436B-8A53-E54FE351C322}別名

#define WSAID_WSARECVMSG \ 
    {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}} 

​​3210は、以下のように定義されます。例えば

:次に

SOCKET sckt = ...; 
LPFN_WSARECVMSG lpWSARecvMsg = NULL; 

GUID g = WSAID_WSARECVMSG; 
DWORD dwBytesReturned = 0; 
if (WSAIoctl(sckt, SIO_GET_EXTENSION_FUNCTION_POINTER, &g, sizeof(g), &lpWSARecvMsg, sizeof(lpWSARecvMsg), &dwBytesReturned, NULL, NULL) != 0) 
{ 
    // WSARecvMsg is not available... 
} 

、それを使用する:

BYTE buffer[...]; 
DWORD dwBytesRecv; 

WSABUF msgbuf; 
memset(&msgbuf, 0, sizeof(msgbuf)); 
msgbuf.len = sizeof(buffer); 
msgbuf.buf = (char *) buffer; 

// call WSA_CMSG_LEN() once for each option you enable 
// on the socket that can return data in WSARecvMsg()... 
int size = WSA_CMSG_LEN(WSA_CMSG_LEN(sizeof(buffer))); 
BYTE *controlbuf = (BYTE *) malloc(size); 

SOCKADDR_STORAGE *addrbuf = (SOCKADDR_STORAGE *) malloc(sizeof(SOCKADDR_STORAGE)); 

WSAMSG msg; 
memset(&msg, 0, sizeof(msg)); 
msg.name = (struct sockaddr *) addrbuf; 
msg.namelen = sizeof(SOCKADDR_STORAGE); 
msg.lpBuffers = &msgbuf; 
msg.dwBufferCount = 1; 
msg.Control.len = size; 
msg.Control.buf = (char *) controlbuf; 

if (lpWSARecvMsg(sckt, &msg, &dwBytesRecv, NULL, NULL) == 0) 
{ 
    // addrbuf contains the sender's IP and port... 
    switch (addrbuf->ss_family) 
    { 
     case AF_INET: 
     { 
      struct sockaddr_in *addr = (struct sockaddr_in*) addrbuf; 
      // use addr as needed... 
      break; 
     } 

     case AF_INET6: 
     { 
      struct sockaddr_in6 *addr = (struct sockaddr_in6*) addrbuf; 
      // use addr as needed... 
      break; 
     } 
    } 

    WSACMSGHDR *msghdr = NULL; 
    do 
    { 
     msghdr = WSA_CMSG_NXTHDR(&msg, msghdr); 
     if (!msghdr) break; 

     switch (msghdr->cmsg_type) 
     { 
      case IP_PKTINFO: // also IPV6_PKTINF 
      { 
       // must call setsockopt(sckt, IPPROTO_IP, IP_PKTINFO, TRUE) beforehand to receive this for IPv4 
       // must call setsockopt(sckt, IPPROTO_IPV6, IPV6_PKTINFO, TRUE) beforehand to receive this for IPv6 

       switch (addrbuf->ss_family) 
       { 
        case AF_INET: 
        { 
         struct in_pktinfo *pktinfo = (struct in_pktinfo *) WSA_CMSG_DATA(msghdr); 
         // use pktinfo as needed... 
         break; 
        } 

        case AF_INET6: 
        { 
         struct in6_pktinfo *pktinfo = (struct in6_pktinfo *) WSA_CMSG_DATA(msghdr); 
         // use pktinfo as needed... 
         break; 
        } 
       } 

       break; 
      } 

      // other packet options as needed... 
     } 
    } 
    while (true); 
} 

free(addrbuf); 
free(controlbuf); 
+0

任意のアイデアを、我々は、エラーC3861 '取得している理由: 'WSARecvMsg' と' WSARecvMsg'を使用した場合、識別子はfound'ありません'#WININE 0x501'(Win XP)を定義しますか?ドキュメントの通り、 'Mswsock.h'が含まれています。ソースファイルにはそれが見えませんか? –

+0

@Ben: 'WSARecvMsg()'のドキュメントをもっと慎重に読んでください。私は、私の答えに関連する引用を付け加えました。 'WSARecvMsg()'関数自体は、どのヘッダファイルにも宣言されていません。あなたのコードで 'Mswsock.hで定義されている' LPFN_WSARECVMSG'型のポインタ変数を宣言し、 'WSAIoctl()'を使って 'WSARecvMsg()'への関数ポインタをその変数に代入しなければなりません。そのポインタを使って必要に応じて 'WSARecvMsg()'を呼び出すことができます。 –

+0

それを読んだ後は明らかですが、最初から最後まで読んでください。 –

関連する問題