gpt4 book ai didi

c - 数据包套接字未接收自定义协议(protocol) ID 的数据

转载 作者:IT王子 更新时间:2023-10-29 00:20:47 24 4
gpt4 key购买 nike

我正在尝试在同一台机器上使用我自己的自定义协议(protocol) ID 通过 PF_SOCKET 发送和接收类型为 SOCK_RAW 的数据包。这是我的发送方和接收方示例代码-

发件人.c

#include<sys/socket.h>
#include<linux/if_packet.h>
#include<linux/if_ether.h>
#include<linux/if_arp.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define CUSTOM_PROTO 0xB588

int main ()
{
int sockfd = -1;
struct sockaddr_ll dest_addr = {0}, src_addr={0};
char *buffer = NULL;
struct ethhdr *eh;

sockfd = socket(PF_PACKET, SOCK_RAW, htons(CUSTOM_PROTO) );

if ( sockfd == -1 )
{
perror("socket");
return -1;
}
buffer = malloc(1518);
eh = (struct ethhdr *)buffer;

dest_addr.sll_ifindex = if_nametoindex("eth0");
dest_addr.sll_addr[0] = 0x0;
dest_addr.sll_addr[1] = 0xc;
dest_addr.sll_addr[2] = 0x29;
dest_addr.sll_addr[3] = 0x49;
dest_addr.sll_addr[4] = 0x3f;
dest_addr.sll_addr[5] = 0x5b;
dest_addr.sll_addr[6] = 0x0;
dest_addr.sll_addr[7] = 0x0;

//other host MAC address
unsigned char dest_mac[6] = {0x0, 0xc, 0x29, 0x49, 0x3f, 0x5b};

/*set the frame header*/
memcpy((void*)buffer, (void*)dest_mac, ETH_ALEN);
memcpy((void*)(buffer+ETH_ALEN), (void*)dest_mac, ETH_ALEN);

eh->h_proto = htons(PAVAN_PROTO);

memcpy((void*)(buffer+ETH_ALEN+ETH_ALEN + 2), "Pavan", 6 );

int send = sendto(sockfd, buffer, 1514, 0, (struct sockaddr*)&dest_addr,
sizeof(dest_addr) );
if ( send == -1 )
{
perror("sendto");
return -1;
}
return 0;
}

接收器.c

#include<sys/socket.h>
#include<linux/if_packet.h>
#include<linux/if_ether.h>
#include<linux/if_arp.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define CUSTOM_PROTO 0xB588

int main ()
{
int sockfd = -1;
struct sockaddr_ll dest_addr = {0}, src_addr={0};
char *recvbuf = malloc(1514);

sockfd = socket(PF_PACKET, SOCK_RAW, htons(CUSTOM_PROTO) );

if ( sockfd == -1 )
{
perror("socket");
return -1;
}
int len = recvfrom(sockfd, recvbuf, 1514, 0, NULL, NULL);
printf("I received: \n");

return 0;
}

发送方和接收方都在 Ubuntu Virtualbox 上运行。问题是接收器在 recvfrom 中挂起。但是在 receiver.c 中,如果我将 htons(CUSTOM_PROTO) 更改为 htons(ETH_P_ALL),接收器工作正常。

为什么内核没有将带有我的自定义协议(protocol) ID 的数据包传送到我的自定义协议(protocol) ID 套接字?

当我使用 htons(ETH_P_ALL) 接收数据包时,我在 GDB 中验证了以太网 header 的格式是否正确

更新:如果我选择本地环回 lo00 的 MAC 地址,而不是接口(interface) eth0 及其对应的 MAC :00:00:00:00:00CUSTOM_PROTO 工作正常!

更新 2 如果发送方和接收方在不同的机器上,CUSTOM_PROTO 工作正常。这个发现和上一个更新让我怀疑在 eth0 上发送的数据包没有被同一台机器接收。但 ETH_P_ALL 在同一台机器上运行的事实驳斥了我的怀疑。

最佳答案

ETH_P_ALL 对比任何其他协议(protocol)

ETH_P_ALL 协议(protocol)具有捕获传出数据包的特殊作用。

具有任何不等于 ETH_P_ALL 的协议(protocol)的接收器套接字接收来自设备驱动程序的该协议(protocol)的数据包。

协议(protocol)为 ETH_P_ALL 的套接字在将传出数据包发送到设备驱动程序之前接收所有数据包,并接收从设备驱动程序接收的所有传入数据包。

环回设备与以太网设备

发送到环回设备的数据包从该设备发出,然后从设备接收到与传入相同的数据包。因此,当 CUSTOM_PROTO 与环回一起使用时,套接字将使用自定义协议(protocol)捕获数据包作为传入。

请注意,如果 ETH_P_ALL 与环回设备一起使用,每个数据包将被接收两次。一次被捕获为传出,第二次被捕获为传入。

eth0 的情况下,数据包从设备传输。因此,此类数据包进入设备驱动程序,然后可以在物理以太网端口的另一侧看到它们。例如,使用 VirtualBox“Host-only”网络适配器,这些数据包可以被主机系统中的一些嗅探器捕获。

但是,传输到物理端口(或其仿真端口)的数据包不会重定向回该端口。因此,它们不会作为来自设备的传入接收。这就是为什么此类数据包只能在传出方向被 ETH_P_ALL 捕获,而在传入方向无法被 CUSTOM_PROTO 捕获。

从技术上讲,应该可以准备特殊的设置来进行外部数据包环回(来自设备端口的数据包应该被发送回该端口)。在那种情况下,行为应该类似于环回设备。

内核实现

查看内核文件net/core/dev.c .有两个不同的列表:

struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;
struct list_head ptype_all __read_mostly; /* Taps */

ptype_all 列表用于协议(protocol)为 ETH_P_ALL 的套接字处理程序。列表 ptype_base 适用于具有正常协议(protocol)的处理程序。

xmit_one() 中有一个用于传出数据包的钩子(Hook)从 dev_hard_start_xmit() 调用:

    if (!list_empty(&ptype_all))
dev_queue_xmit_nit(skb, dev);

对于传出数据包,函数 dev_queue_xmit_nit() 被调用用于 ETH_P_ALL 处理 ptype_all 的每个项目。最后,类型为 AF_SOCKET 且协议(protocol)为 ETH_P_ALL 的套接字捕获该传出数据包。


因此,观察到的行为与任何自定义协议(protocol)无关。使用 ETH_P_IP 可以观察到相同的行为。在这种情况下,接收方能够捕获所有传入的 IP 数据包,但是它无法捕获从 "eth0" 发送到 的 MAC 地址的 sender.c 的 IP 数据包>“eth0” 设备。

也可以通过tcpdump看到。如果调用 tcpdump 并带有仅捕获传入数据包的选项,则不会捕获发送方发送的数据包(不同版本的 tcpdump 使用不同的命令行参数来启用此类过滤) .


在同一台机器上需要通过协议(protocol) ID 区分数据包的初始任务可以使用 ETH_P_ALL 来解决。接收方应捕获所有数据包并检查协议(protocol),例如:

while (1) {
int len = recvfrom(sockfd, recvbuf, 1514, 0, NULL, NULL);

if (ntohs(*(uint16_t*)(recvbuf + ETH_ALEN + ETH_ALEN)) == CUSTOM_PROTO) {
printf("I received: \n");
break;
}
}

有用的引用 "kernel_flow"有一个漂亮的图表 http://www.linuxfoundation.org/images/1/1c/Network_data_flow_through_kernel.png

它基于 2.6.20 内核,但是在现代内核中 ETH_P_ALL 以相同的方式处理。

关于c - 数据包套接字未接收自定义协议(protocol) ID 的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33484762/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com