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

  • IP报头中的协议类型

    在定位IP报头后,就可以根据其中的协议类型protocol来区分是IP层下的哪一种协议,主要协议类型即对应值如下:

协议类型
ICMP1
IGMP2
TCP6
UDP17
  • 定位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的类似,这里就不再赘述了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值