利用libpcap抓包(二)----------网络数据包头结构定义

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Sophisticated_/article/details/83339048

这里在head.h的头文件中定义了以太网,IP, PPPOE, ARP, TCP, UDP 等数据包头部的结构体,以便于对数据包进行解析,其实在库中有已经定义好的各个数据包头部,像ethhdr,iphdr,tcphdr等,这里自己写一遍可以加深对网络数据包的理解。

/******************************************************************************
  文 件 名   : head.h
  版 本 号   : V1.1
  负 责 人   : Sophisticated
  生成日期   : 2018年9月27日
  最近修改   :
  文件描述   : 报文头部结构体
  函数列表   :
  修改历史   :
  1.日    期   : 2018年9月27日
    作    者   : Sophisticated
    修改内容   : 创建文件

******************************************************************************/

#ifndef _HEAD_H_
#define _HEAD_H_

#include<sys/types.h>
#include<netinet/in.h>

/*最大抓包长度 :Ethernet 1500字节 + 以太网帧头部14字节 + 以太网帧尾部4字节*/
#define SNAP_LEN 1518

/*ethernet head are exactly 14 bytes*/
#define ETHERNET_HEAD_SIZE 14

/*ip头部字节数宏  取hlv低四位即头部长度*单位4bytes  然后强转为ip结构体*/
//#define IP_HEAD_SIZE(ipheader) ((ipheader->ip_hlv & 0x0f) * 4)
#define IP_HEAD_SIZE(packet)  ((((struct ip *)(packet + ETHERNET_HEAD_SIZE))->ip_hlv & 0x0f) * 4)

/*ethernet address are 6 bytes*/
#define ETHERNET_ADDR_LEN 6

/*ip address are 4 bytes*/
#define IP_ADDR_LEN 4

#define ARP_REQUEST 1
#define ARP_REPLY 2

/*TCP flag*/
#define TCP_FIN 0x01
#define TCP_SYN 0x02
#define TCP_RST 0x04
#define TCP_PUSH 0x08
#define TCP_ACK 0x10
#define TCP_URG 0x20
#define TCP_ECE 0x40
#define TCP_CWR 0x80

/*Ethernet HEADER*/
struct ethernet
{
	u_char ether_dhost[ETHERNET_ADDR_LEN];
	u_char ether_shost[ETHERNET_ADDR_LEN];
	u_short ether_type;  //IP?ARP?etc
};

/*IP HEADER*/
struct ip
{
	//unsigned int ip_version:4;  
	//unsigned int ip_hlen:4;
	u_char ip_hlv; /*version + headlength 如果分开定义会有大小端问题,会增加额外的判断*/
	u_char ip_tos;
	u_short ip_len;
	u_short ip_id;
	u_short ip_off;
	u_char ip_ttl;
	u_char ip_protocol;
	u_short ip_sum;
	u_char ip_src[IP_ADDR_LEN];
	u_char ip_dst[IP_ADDR_LEN];
};

/*TCP HEADER*/
struct tcp
{
	u_short tcp_sport;
	u_short tcp_dport;
	u_int tcp_seqe;
	u_int tcp_ack;
	
	//u_char tcp_off:4;
	//u_char tcp_unused:4;  //保留位
	u_char tcp_hre;  //header(4bits) + reserved(4bits)
	u_char tcp_flag;
	u_short tcp_win;
	u_short tcp_sum;
	u_short tcp_urp;
};

/*UDP HEADER*/
struct udp
{
	u_short udp_sport;
	u_short udp_dport;
	u_short udp_len;
	u_short udp_sum;
};

/*ARP HEADER 8+6+4+6+4*/
struct arp
{
	u_short arp_hrd; //hardware
	u_short arp_pro;  //protocol
	u_char arp_hdlen; //hardware address length
	u_char arp_prolen; //protocol length
	u_short arp_op;  //arp operations
	u_char arp_shost[ETHERNET_ADDR_LEN];
	u_char arp_sip[IP_ADDR_LEN];
	u_char arp_dhost[ETHERNET_ADDR_LEN];
	u_char arp_dip[IP_ADDR_LEN];
};

/*ICMP HEADER*/
struct icmp
{
	u_char icmp_type;
	u_char icmp_code;
	u_short icmp_sum;
	u_short icmp_id;
	u_short icmp_seq;
	u_int icmp_time;
};

/*PPPOE HEADER*/
struct pppoe
{
    u_char pppoe_vtype;  //version(0x1) + type(0x1)
    u_char pppoe_code;
    u_short pppoe_s_id;
    u_short pppoe_len;
}
#endif

说明

在定义IP数据包头结构的第一个字节时,即IP版本号和数据报头长度,我和源码中的做法不太一样,源码中是这样:

#if defined(__LITTLE_ENDIAN_BITFIELD)
	__u8	ihl:4,
		version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
	__u8	version:4,
  		ihl:4;
#else
#error	"Please fix <asm/byteorder.h>"
#endif
......

而我是把版本号和报文头长度一起定义在了一个字节里,这样不用区分大小端问题,只是解析起来会麻烦些。
解析方法:

ipheader->ip_hlv & 0xf0) >> 4
取这个字节高四位即为版本号
ipheader->ip_hlv & 0x0f
取这个字节低四位即为报文头长度

在定义tcp数据包头结构体时也是如此,我把标志位flag定义到一个字节里了,源码中是这样的:

#if defined(__LITTLE_ENDIAN_BITFIELD)
	__u16	res1:4,
		doff:4,
		fin:1,
		syn:1,
		rst:1,
		psh:1,
		ack:1,
		urg:1,
		ece:1,
		cwr:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
	__u16	doff:4,
		res1:4,
		cwr:1,
		ece:1,
		urg:1,
		ack:1,
		psh:1,
		rst:1,
		syn:1,
		fin:1;
#else
#error	"Adjust your <asm/byteorder.h> defines"
#endif

解析方法见后面的tcp报文头部解析函数,同样是使用的&运算

猜你喜欢

转载自blog.csdn.net/Sophisticated_/article/details/83339048