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

我还没有找到sendmsg()如何与原始套接字一起工作的任何示例,但是使用sendto()的类似代码可以按预期工作。在该代码中,我明确地形成了以太网帧,包括 header 和协议(protocol)信息,但是据我了解,使用sendmsg()调用不是必需的吗?我也尝试过使message.iov_base指向一个缓冲区,该缓冲区包含包含14字节 header 的显式格式的以太网帧,但是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 }

最佳答案

经过一些调整后,我得到了这段代码。

我没有使用sendmsg()的手册页中所暗示的那样以字节字符串形式发送地址,而是使用了struct sockaddr_ll。我也将iovec指向包含完整以太网帧(包括 header )的缓冲区。为什么手册页在const struct sockaddr*原型(prototype)中显式指定了sendto,但在void*定义中却指定了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);

关于c - 将sendmsg/sendmmsg与原始以太网帧一起使用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37976001/

10-12 19:58