c语言 - 将 sendmsg/sendmmsg 与原始以太网帧一起使用



我正在尝试使用 C 通过sendmsg()发送原始以太网数据包。 此代码成功打开原始数据包套接字,尝试用单个字节数组 (char message[]) 填充struct iovec,然后用目标地址、地址长度和指向包含消息struct iovec的指针填充struct msghdrsendmsg()每次调用都返回EINVAL,但我不知道哪些参数无效。(我删除了一些perror()调用以使此代码更易于阅读;输出Invalid argument

我无法找到任何关于sendmsg()如何使用原始套接字的示例,但使用sendto()的类似代码按预期工作。在该代码中,我显式地形成以太网帧,包括标头和协议信息,但据我了解,sendmsg()调用不需要吗?我还试图让message.iov_base指向一个包含显式格式的以太网帧(包括 14 字节标头)的缓冲区,but 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: %sn", 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 }

经过一些调整后,我让这段代码工作了。

我没有像手册页所暗示的那样将地址作为字节字符串发送sendmsg(),而是使用了struct sockaddr_ll。我还iovec指向一个缓冲区,其中包含完整的以太网帧,包括标头。为什么手册页在sendto原型中明确指定了const struct sockaddr*,而在msghdr定义中指定了void*,我仍然不知道。

我在调用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);

最新更新