定位IP报头
获得以太网帧后,当协议类型为0x0800时,其负载部分协议为IP协议,及以太网帧中的数据部分,从第46字节开始的前20个字节,就是IP报头。数据结构如下:
IP头部的数据结构定义在头文件【netinet/ip.h】中,如下:
struct iphdr
{
#if __BYTE_ORDER == __LITTLE_ENDIAN /*小端*/
unsigned int ihl:4; /*IP头部长度,单位为32bit*/
unsigned int version:4; /*IP版本,值为4*/
#elif __BYTE_ORDER == __BIG_ENDIAN /*大端*/
unsigned int version:4; /*IP版本,值为4*/
unsigned int ihl:4; /*IP头部长度,单位为32bit*/
#else
# error "Please fix <bits/endian.h>"
#endif
u_int8_t tos; /*服务类型*/
u_int16_t tot_len; /*总长度*/
u_int16_t id; /*标识*/
u_int16_t frag_off; /*片偏移*/
u_int8_t ttl; /*生存时间*/
u_int8_t protocol; /*协议类型*/
u_int16_t check; /*头部校验和*/
u_int32_t saddr; /*源IP地址*/
u_int32_t daddr; /*目的IP地址*/
/*The options start here. */
};
在捕获的以太网帧中h_proto的取值为0x0800后,将类型为iphdr的结构指针指向以太网的帧头的数据部分的起始位置,就可以得到IP数据包的报头部分了。通过saddr和daddr可以得到IP报文的源IP地址和目的IP地址,具体使用如下:
switch (proto_type_ethHdr)
{
case(0x0800): //IP协议
struct iphdr *p_ipHdr = (struct iphdr *)(buffer + sizeof(ethhdr));
unsigned char* p_src_ip, p_dst_ip;
p_src_ip = (unsigned char*)&ipHdr->saddr;
p_dst_ip = (unsigned char*)&ipHdr->daddr;
src_ip_str.sprintf("%u.%u.%u.%u", p_src_ip[0], p_src_ip[1], p_src_ip[2], p_src_ip[3]);
dst_ip_str.sprintf("%u.%u.%u.%u",p_dst_ip[0], p_dst_ip[1], p_dst_ip[2], p_dst_ip[3]);
qDebug() << src_ip_str; //打印
qDebug() << dst_ip_str;
break;
case(0x0806): //ARP协议
break;
case(0x8035): //RARP协议
break;
}