我正在尝试使用 C 通过 sendmsg 发送原始以太网数据包。此代码成功打开原始数据包套接字,尝试用单个字节数组 (char message[]) 填充 struct iovec,然后用目标地址、地址长度和指向包含 struct iovec 的指针填充 struct msghdr消息。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 }