IP报头中的协议类型
在定位IP报头后,就可以根据其中的协议类型protocol来区分是IP层下的哪一种协议,主要协议类型即对应值如下:
协议类型 | 值 |
---|---|
ICMP | 1 |
IGMP | 2 |
TCP | 6 |
UDP | 17 |
定位TCP报头
TCP的数据结构如下图所示:
在【netinet/tcp.h】中的定义如下:
/*
* TCP header.
* Per RFC 793, September, 1981.
*/
struct tcphdr
{
__extension__ union
{
struct
{
u_int16_t th_sport; /* source port */
u_int16_t th_dport; /* destination port */
tcp_seq th_seq; /* sequence number */
tcp_seq th_ack; /* acknowledgement number */
# if __BYTE_ORDER == __LITTLE_ENDIAN
u_int8_t th_x2:4; /* (unused) */
u_int8_t th_off:4; /* data offset */
# endif
# if __BYTE_ORDER == __BIG_ENDIAN
u_int8_t th_off:4; /* data offset */
u_int8_t th_x2:4; /* (unused) */
# endif
u_int8_t th_flags;
# define TH_FIN 0x01
# define TH_SYN 0x02
# define TH_RST 0x04
# define TH_PUSH 0x08
# define TH_ACK 0x10
# define TH_URG 0x20
u_int16_t th_win; /* window */
u_int16_t th_sum; /* checksum */
u_int16_t th_urp; /* urgent pointer */
};
struct
{
u_int16_t source;
u_int16_t dest;
u_int32_t seq;
u_int32_t ack_seq;
# if __BYTE_ORDER == __LITTLE_ENDIAN
u_int16_t res1:4;
u_int16_t doff:4;
u_int16_t fin:1;
u_int16_t syn:1;
u_int16_t rst:1;
u_int16_t psh:1;
u_int16_t ack:1;
u_int16_t urg:1;
u_int16_t res2:2;
# elif __BYTE_ORDER == __BIG_ENDIAN
u_int16_t doff:4;
u_int16_t res1:4;
u_int16_t res2:2;
u_int16_t urg:1;
u_int16_t ack:1;
u_int16_t psh:1;
u_int16_t rst:1;
u_int16_t syn:1;
u_int16_t fin:1;
# else
# error "Adjust your <bits/endian.h> defines"
# endif
u_int16_t window;
u_int16_t check;
u_int16_t urg_ptr;
};
};
};
其中,我们主要关注的是源端口号,目的端口号,序列号以及确认序列号。主要代码如下:
QString src_port_str;
QString dst_port_str;
QString tcp_seq_str;
QString tcp_ack_seq_str;
struct tcphdr *p_tcpHdr;
p_tcpHdr = (struct tcphdr *)(buffer + sizeof(ethhdr)+sizeof(iphdr));
src_port_str.sprintf("Src Port:%d",htons(p_tcpHdr->source));
dst_port_str.sprintf("Dest Port:%d",htons(p_tcpHdr->dest));
tcp_seq_str.sprintf("Sequence Number:%d",htonl(p_tcpHdr->seq));
tcp_ack_seq_str.sprintf("Acknowledgment Number:%d", htonl(p_tcpHdr->ack_seq));
qDebug()<<src_port_str;
qDebug()<<dst_port_str;
qDebug()<<tcp_seq_str;
qDebug()<<tcp_ack_seq_str;
对于TCP协议,其IP头部的protocol的值为6,在存储接收数据的缓冲区buffer里面,其偏移大小为(以太网帧头部长度+IP报文头部长度)。这部分可以结合计算机网络中TCP协议对数据的封装解封过程来理解。接收数据的过程就是一个解封包的过程,我们从以太网帧的数据解封为IP层的数据,再到TCP。分析数据包中的数据也是类似的。
定位UDP报头
UDP的数据结构如下:
UDP的头部数据结构定义在头文件【netinet/udp.h】中,如下:
/* UDP header as specified by RFC 768, August 1980. */
struct udphdr
{
__extension__ union
{
struct
{
u_int16_t uh_sport; /* source port */
u_int16_t uh_dport; /* destination port */
u_int16_t uh_ulen; /* udp length */
u_int16_t uh_sum; /* udp checksum */
};
struct
{
u_int16_t source;
u_int16_t dest;
u_int16_t len;
u_int16_t check;
};
};
};
对于UDP协议,其IP头部的protocol的值为17。其报头定位与TCP是一样的。代码如下:
QString src_port_str;
QString dst_port_str;
QString udp_pack_len;
QString udp_checksum;
struct udphdr *p_udpHdr;
p_udpHdr = (struct tcphdr *)(buffer+sizeof(ethhdr)+sizeof(iphdr));
src_port_str.sprintf("Src Port:%d",htons(p_udpHdr->source));
dst_port_str.sprintf("Dest Port:%d",htons(p_udpHdr->dest));
udp_pack_len.sprintf("Length:%d",htons(udpHdr->len));
udp_checksum.sprintf("Checksum:0x%04x", htons(udpHdr->check));
qDebug()<<src_port_str;
qDebug()<<dst_port_str;
qDebug()<<udp_pack_len;
qDebug()<<udp_checksum;
定位应用层报文数据
当我们定位了UDP或者是TCP的头部地址后,它们的数据部分就是应用层报文数据了,定位方式与TCP或UDP的类似,这里就不再赘述了。