11.4.4 定位IP包头的编程方法
获得以太网帧后,当协议为0x0800时,其负载部分为IP协议。IP协议的数据结构如图11.12所示。
图11.12 IP数据的示意图
IP头部的数据结构定义在头文件<Linux/ip.h>中,代码如下:
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)/*小端*/
__u8 ihl:4, /*IP头部长度,单位为32bit*/
version:4; /*IP版本,值为4*/
#elif defined (__BIG_ENDIAN_BITFIELD)/*大端*/
__u8 version:4, /*IP版本,值为4*/
ihl:4; /*IP头部长度,单位为32bit*/
#else
#error "Please fix <asm/byteorder.h>"
#endif
__u8 tos; /*服务类型*/
__be16 tot_len; /*总长度*/
__be16 id; /*标识*/
__be16 frag_off; /*片偏移*/
__u8 ttl; /*生存时间*/
__u8 protocol; /*协议类型*/
__u16 check; /*头部校验和*/
__be32 saddr; /*源IP地址*/
__be32 daddr; /*目的IP地址*/
/*IP选项*/
};
若捕获的以太帧中h_proto的取值为0x0800,将类型为iphdr的结构指针指向帧头后面载荷数据的起始位置,则可以得到IP数据包的报头部分。通过saddr和daddr可以得到IP报文的源IP地址和目的IP地址,下面的代码打印IP报文的源IP地址和目的IP地址。
/*打印IP报文的源IP地址和目的IP地址*/
if(ntohs(p_ethhdr->h_proto)==0x0800) /*0x0800:IP包*/
{
/*定位IP头部*/
struct iphdr*p_iphdr = (struct iphdr*) (ef + ETH_HLEN);
/*打印源IP地址*/
printf("src ip:%s/n", inet_ntoa(p_iphdr->saddr));
/*打印目的IP地址*/
printf("dest ip:%s/n", inet_ntoa(p_iphdr->daddr));