6

C を使用して、sendmsg 経由で生のイーサネット パケットを送信しようとしています。このコードは、正常に生のパケット ソケットを開き、1 つのバイト配列 (char message[]) で struct iovec を埋めようとし、次に struct msghdr を宛先アドレス、アドレス長、および struct iovec を含む struct iovec へのポインタで埋めます。メッセージ。sendmsg() は呼び出しごとに EINVAL を返しますが、どの引数が無効かわかりません。(このコードを読みやすくするために、いくつかの perror() 呼び出しを削除しました。出力は「無効な引数」です。)

sendmsg() が生のソケットでどのように機能するかの例を見つけることができませんでしたが、sendto() を使用した同様のコードは期待どおりに機能します。そのコードでは、ヘッダーとプロトコル情報を含めてイーサネット フレームを明示的に形成しますが、sendmsg() 呼び出しでは必要ないことを理解していますか? また、message.iov_base が、14 バイトのヘッダーを含む明示的に形成されたイーサネット フレームを含むバッファーを指すようにしようとしましたが、sendmsg() もそれを妨げます。

sendmsg() と sendmmsg() は生のイーサネット フレームで動作しますか? 無効にしている iovec について私が見逃しているものはありますか?

 30 int main(void) {
 32         unsigned char   dest[ETH_ALEN] = {0x11, 0x11, 0x11, 0x11, 0x11, 0x11}; // destination MAC address
 33
 34         // Socket variables
 35         int             s;  
 36         unsigned short  protocol = htons(ETH_P_802_EX1); 
 38 
 39         // Message variables
 40         char            message[] = {"Test message. Test message. Test message!\n"};
 41         size_t          msg_len = strlen(message) + 1;          // Message length includes null terminator
 42         int             e;                                      // Error code
 43         struct msghdr   msg;
 44         struct iovec    msgvec;
 45 
 46         // Setup source-side socket
 47         s = socket(AF_PACKET, SOCK_RAW, protocol);
 48         if (s < 0) { printf("%d: %s\n", errno, strerror(errno)); return EXIT_FAILURE; }
 49 
 50         msgvec.iov_base = message;
 51         msgvec.iov_len = msg_len;
 52         memset(&msg, 0, sizeof(msg));
 53         msg.msg_name = dest;
 54         msg.msg_namelen = ETH_ALEN;
 55         msg.msg_control = NULL;
 56         msg.msg_controllen = 0;
 57         msg.msg_flags = 0;
 65         msg.msg_iov = &msgvec;
 66         msg.msg_iovlen = 1;
 67 
 68         for (int i=0; i<10; i++) {
 69                 e = sendmsg(s, &msg, 0);
 73         }
 79         close(s);
 80         return EXIT_SUCCESS;
 81 }
4

1 に答える 1

6

いくつかの調整を行った後、このコードが機能するようになりました。

のマニュアル ページで暗示されているようにアドレスをバイト文字列として送信する代わりにsendmsg()struct sockaddr_ll. また、iovecヘッダーを含む完全なイーサネット フレームを含むバッファーも指定しました。プロトタイプconst struct sockaddr*では a が明示的に指定されているのに、定義ではa がマニュアル ページで明示的に指定されている理由は、私にはわかりません。sendtovoid*msghdr

への呼び出しの後にこのコードを追加しましたsocket():

 39         struct sockaddr_ll address;
 40         struct ifreq    buffer;                                 // To get information with ioctl()
 41         char            ifname[] = {"eth0"};
 42         int             ifindex;                                // Interface index, from ioctl() call

 57         memset(&buffer, 0, sizeof(buffer));                     // Getting interface index value
 58         strncpy(buffer.ifr_name, ifname, IFNAMSIZ);
 59         ioctl(s, SIOCGIFINDEX, &buffer);
 60         ifindex = buffer.ifr_ifindex;
 61
 62         // Setup sockaddr_ll address
 63         memset( (void*) &address, 0, sizeof(address) );
 64         address.sll_family = PF_PACKET;
 65         address.sll_ifindex = ifindex;
 66         address.sll_halen = ETH_ALEN;
 67         memcpy( (void*) (address.sll_addr), (void*) dest, ETH_ALEN );

msghdr 構造体割り当てのコード行を次のように置き換えます。

 81         msg.msg_name = &address;
 82         msg.msg_namelen = sizeof(address);
于 2016-06-22T19:30:45.937 に答える