AF_PACKET 和以太网
AF_PACKET and Ethernet
我很困惑 AF_PACKET
套接字系列(对于 SOCK_RAW
套接字)与以太网 (IEEE 802.3) 的具体关系。
目前我的理解:
我了解 OSI 模型,以及第 2 层技术如何
以太网适合模型。
我知道 AF_PACKET
可以与 SOCK_RAW
套接字一起使用
接收包含 14 字节以太网 header 的数据报,后跟一些
其他高层协议header(s),如IPv4、IPv6等,
其次是可选的传输层协议,如 TCP,以及
终于是一个有效载荷。
我知道您可以将 ETH_P_ALL
或 ETH_P_IP
等标志传递为
socket
的协议参数让内核过滤数据包
对你来说,只向你发送包含 headers 的数据包
类型。
- 我知道使用
AF_PACKET
系列创建的套接字可以接收或发送到 sockaddr_ll
类型的端点,它与特定的 MAC 地址(EUI-48 地址)相关联,以及特定的网络接口(例如 eth0
或其他)。
不明白的地方:
我不明白 AF_PACKET
是否应该专门用于以太网设备,而不是其他第 2 层技术,例如 Wifi、蓝牙、令牌环、Infiniband 等.
我不明白以太网 设备 与使用 14 字节 的第 2 层协议之间的关系以太网 header。以太网 header 是 14 个字节,可以这样定义: struct eth_hdr { char dest_address[6]; char source_address[6]; uint16_t ethertype; };
换句话说,这个 header 是否只用于物理以太网设备?看来答案是no,因为如果我在环回接口上使用AF_PACKET
,我仍然会收到包含14字节的数据包以太网header s。但是环回 不是 以太网设备。那么为什么它会收到包含以太网 headers 的数据包?
如果 AF_PACKET
可以与 non-Ethernet 设备一起使用,ETH_P_ALL
协议标志是否指示只接受专门具有 14 字节以太网的数据包 header?
我的问题:
使用 AF_PACKET
是否意味着您保证 始终 接收具有 14 字节以太网 header 的数据包?
如果是这样,是否也意味着 AF_PACKET
只能用于以太网设备(与其他第 2 层技术相反,如 Wifi、令牌环、蓝牙、Infiniband 等)?
如果这些问题中的任何一个的答案是 否,那么应用程序如何以编程方式确定在接收数据报时预期的第 2 层类型 header AF_PACKET
插座?
警告: 这是因为我为使用 PF_PACKET
的生产软件编写的一些代码进行了蚕食,这些代码仅适用于以太网,因此 可能 为 incomplete/inaccurate.
您正在使用 ETH_P_ALL
,将 为您提供任何东西。但是,有许多 ETH_P_*
符号可供选择(例如 ETH_P_802_3_MIN
)。
binding/selection 不仅基于 socket
调用,还基于给定的 接口 。
首先你需要你想要的接口名称(例如eth0
),你可以从ifconfig
.
获得列表
然后,使用 ioctl(SIOCGIFINDEX,...)
从接口名称中获取接口 index [或者,您可以硬编码它,因为 ifconfig
会打印出来按索引顺序]。
然后,根据接口索引,bind
到那个接口。
既然你知道接口的类型(例如你选择eth0
或wifi等),之后,你应该能够消化物理层header因为你知道它是否是struct eth_hdr
与否。
请注意,您可以使用许多其他 SIOCGIF*
ioctl 来获取接口列表和其他信息,这些信息可以让您辨别接口类型 [以及因此,物理 header期待].
无论如何,这是我所做的一些示例代码:
int
init(const char *intf)
// intf -- interface name (e.g. eth0, etc. -- whatever comes from ifconfig)
{
int err;
#if 1
int styp = SOCK_RAW;
#else
int styp = SOCK_DGRAM;
#endif
int netsock = socket(PF_PACKET,styp,htons(ETH_P_ALL));
struct ifreq ifr;
memset(&ifr,0,sizeof(ifr));
strncpy(ifr.ifr_name,intf,sizeof(ifr.ifr_name));
// get the index number of the interface
err = ioctl(netsock,SIOCGIFINDEX,&ifr);
if (err < 0)
do_whatever;
printf("init: IFRIDX ifr_ifindex=%d\n",ifr.ifr_ifindex);
int ifidx = ifr.ifr_ifindex;
struct sockaddr_ll addr;
addr.sll_family = AF_PACKET;
addr.sll_protocol = htons(ETH_P_ALL);
addr.sll_ifindex = ifidx;
err = bind(netsock,(struct sockaddr *) &addr,
sizeof(struct sockaddr_ll));
if (err < 0)
do_whatever;
return netsock;
}
我很困惑 AF_PACKET
套接字系列(对于 SOCK_RAW
套接字)与以太网 (IEEE 802.3) 的具体关系。
目前我的理解:
我了解 OSI 模型,以及第 2 层技术如何 以太网适合模型。
我知道
AF_PACKET
可以与SOCK_RAW
套接字一起使用 接收包含 14 字节以太网 header 的数据报,后跟一些 其他高层协议header(s),如IPv4、IPv6等, 其次是可选的传输层协议,如 TCP,以及 终于是一个有效载荷。我知道您可以将
ETH_P_ALL
或ETH_P_IP
等标志传递为socket
的协议参数让内核过滤数据包 对你来说,只向你发送包含 headers 的数据包 类型。- 我知道使用
AF_PACKET
系列创建的套接字可以接收或发送到sockaddr_ll
类型的端点,它与特定的 MAC 地址(EUI-48 地址)相关联,以及特定的网络接口(例如eth0
或其他)。
不明白的地方:
我不明白
AF_PACKET
是否应该专门用于以太网设备,而不是其他第 2 层技术,例如 Wifi、蓝牙、令牌环、Infiniband 等.我不明白以太网 设备 与使用 14 字节 的第 2 层协议之间的关系以太网 header。以太网 header 是 14 个字节,可以这样定义:
struct eth_hdr { char dest_address[6]; char source_address[6]; uint16_t ethertype; };
换句话说,这个 header 是否只用于物理以太网设备?看来答案是no,因为如果我在环回接口上使用AF_PACKET
,我仍然会收到包含14字节的数据包以太网header s。但是环回 不是 以太网设备。那么为什么它会收到包含以太网 headers 的数据包?如果
AF_PACKET
可以与 non-Ethernet 设备一起使用,ETH_P_ALL
协议标志是否指示只接受专门具有 14 字节以太网的数据包 header?
我的问题:
使用 AF_PACKET
是否意味着您保证 始终 接收具有 14 字节以太网 header 的数据包?
如果是这样,是否也意味着 AF_PACKET
只能用于以太网设备(与其他第 2 层技术相反,如 Wifi、令牌环、蓝牙、Infiniband 等)?
如果这些问题中的任何一个的答案是 否,那么应用程序如何以编程方式确定在接收数据报时预期的第 2 层类型 header AF_PACKET
插座?
警告: 这是因为我为使用 PF_PACKET
的生产软件编写的一些代码进行了蚕食,这些代码仅适用于以太网,因此 可能 为 incomplete/inaccurate.
您正在使用 ETH_P_ALL
,将 为您提供任何东西。但是,有许多 ETH_P_*
符号可供选择(例如 ETH_P_802_3_MIN
)。
binding/selection 不仅基于 socket
调用,还基于给定的 接口 。
首先你需要你想要的接口名称(例如eth0
),你可以从ifconfig
.
然后,使用 ioctl(SIOCGIFINDEX,...)
从接口名称中获取接口 index [或者,您可以硬编码它,因为 ifconfig
会打印出来按索引顺序]。
然后,根据接口索引,bind
到那个接口。
既然你知道接口的类型(例如你选择eth0
或wifi等),之后,你应该能够消化物理层header因为你知道它是否是struct eth_hdr
与否。
请注意,您可以使用许多其他 SIOCGIF*
ioctl 来获取接口列表和其他信息,这些信息可以让您辨别接口类型 [以及因此,物理 header期待].
无论如何,这是我所做的一些示例代码:
int
init(const char *intf)
// intf -- interface name (e.g. eth0, etc. -- whatever comes from ifconfig)
{
int err;
#if 1
int styp = SOCK_RAW;
#else
int styp = SOCK_DGRAM;
#endif
int netsock = socket(PF_PACKET,styp,htons(ETH_P_ALL));
struct ifreq ifr;
memset(&ifr,0,sizeof(ifr));
strncpy(ifr.ifr_name,intf,sizeof(ifr.ifr_name));
// get the index number of the interface
err = ioctl(netsock,SIOCGIFINDEX,&ifr);
if (err < 0)
do_whatever;
printf("init: IFRIDX ifr_ifindex=%d\n",ifr.ifr_ifindex);
int ifidx = ifr.ifr_ifindex;
struct sockaddr_ll addr;
addr.sll_family = AF_PACKET;
addr.sll_protocol = htons(ETH_P_ALL);
addr.sll_ifindex = ifidx;
err = bind(netsock,(struct sockaddr *) &addr,
sizeof(struct sockaddr_ll));
if (err < 0)
do_whatever;
return netsock;
}