WSASendToを試してみた

任意のIPパケットを送りたいという動機で、WSASendToを使ってみました。

bool RawSocket::Write(byte* buff, dword size, dword* writeSize)
{
    unsigned long length;
    unsigned long flags = 0;
    IP::Header* h = (IP::Header*)buff;
    SOCKADDR_IN addr_in;
    addr_in.sin_addr.s_addr = h->dstip;
    addr_in.sin_family      = AF_INET;              // IPv4
    addr_in.sin_port        = htons(0);             // 0で初期化らしい

    WSABUF wsb;
    wsb.buf = (PTCHAR)buff;
    wsb.len = size;

//    if (SOCKET_ERROR == WSASend(this->socket, &wsb, 1, &length, flags, NULL, NULL))
//    if (SOCKET_ERROR == sendto(this->socket, wsb.buf, sizeof(wsb.buf), 0, (SOCKADDR*)&addr_in, sizeof(addr_in)))
    if (SOCKET_ERROR == WSASendTo(this->socket, &wsb, 1, &length, flags, (struct sockaddr *)&addr_in, sizeof(SOCKADDR_IN), NULL, NULL))
    {
        TRACE("SEND ERROR \n");
        return false;
    }
    *writeSize = length;
    return true;
}

これを利用して先日のsocket.Readで受信した、自分宛のパケットをちょっとだけ改変して、自分自身に送ってみました。

        header->srcip = inet_addr("192.168.10.1");
        header->prot = 7;
        memset(header->data, 0xef, sizeof(header->data));
        if (!socket.Write( (byte*)header, sizeof(IP::Header), &length) )
        {
            printf("Write Error:%s\n", socket.GetErrorMessage() );
        }

結果がこちら

Waiting for Packet...
protocol number 0
source   address 192.168.11.2
dest     address 192.168.11.2
data     45 00 00 28 ffffffb1 fffffff2 40 00 36 07

確かに自分から自分へ送受信できているのですが、ちょっと様子がおかしいです。
srcipの書き換えやらがぜんぜん無視されてます(´ヘ`;)
bufの中身はIPHeaderを渡しているのですが、どうもこれがIPHeaderとして送られているのではなくて、IPHeaderは勝手に作られてしまっているようです。


なんだかWSASendToが目的の関数じゃない予感がしてきました・・・。
というわけで微妙にパケットが送れているソースを置いておきます。
rawsock-20051126.zip

あまりこれにはまって、時間をとられるのもあれだからもう少しがんばってだめならあきらめよう。

追記:2005/12/21
その後の調査によりWindows XP SP2のセキュリティ向上によりRawSocketによる送信は制限されていることが分かりました。
WinPcapによる実装をおすすめします。
RawSocketに関してはid:higepon:20051207:1133963958
WinPcapに関してはid:higepon:20051209:1134143054
辺りに書いてあります。