![为什么以太网帧中IP协议的协议类型值为8?](https://linux22.com/image/130705/%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BB%A5%E5%A4%AA%E7%BD%91%E5%B8%A7%E4%B8%ADIP%E5%8D%8F%E8%AE%AE%E7%9A%84%E5%8D%8F%E8%AE%AE%E7%B1%BB%E5%9E%8B%E5%80%BC%E4%B8%BA8%EF%BC%9F.png)
我正在编写一个简单的数据包处理程序。这是代码摘录:
void print_ethernet_header(unsigned char* buffer)
{
struct ethhdr *eth = (struct ethhdr *)buffer;
fprintf(logfile , " |-Protocol : %x \n",eth->h_proto);
}
这个简单的函数应该将协议类型的十六进制值打印到日志文件中。事实上它确实打印了值“8”。但是,在源 /usr/include/net/ethernet.h 和在线中(https://en.wikipedia.org/wiki/EtherType)我看到IP协议类型被定义为0x0800。所以我实际上期望看到值 800(十六进制)或 2048(十进制)打印到文件,而不是 8。我认为这可能与字节顺序有关,并且需要从网络字节顺序转换为主机,但在recvfrom() 手册页中没有找到任何有关此内容的信息。这是填充缓冲区变量的调用:
sock_raw = socket(AF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
//some code here...
data_size = recvfrom(sock_raw , buffer , bufsize , 0 , (struct sockaddr*)&saddr , (socklen_t*)&saddr_size);
我工作的机器是小端(Ubuntu 16.04)。为什么协议类型显示8?
答案1
结构定义显示这h_proto
是一个大端 16 位整数:
struct ethhdr {
unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
unsigned char h_source[ETH_ALEN]; /* source ether addr */
__be16 h_proto; /* packet type ID field */
} __attribute__((packed));
ntohs
所以你在阅读之前确实需要对其进行处理。执行此操作后,您将看到正确的值 0x0800。
答案2
如果您尝试打印该 EtherType 广告,但没有获得正确的值,则表明您的机器未以正确的方式解释字节序。解决方案将是:
int etherType = ntohs(eth->h_proto);
printf("EtherType: 02%x", etherType);
这将为您提供文档中指定的 EtherType。