简易版WireShark实现-相关网络知识(3)

来源:互联网 发布:mac中文解压软件 编辑:程序博客网 时间:2024/06/10 10:39
  • 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的类似,这里就不再赘述了。