简易版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的类似,这里就不再赘述了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 实现简易版wireshark需要先了解一些基础知识Wireshark是一款流行的网络封包分析工具,它可以用于捕获和分析网络数据包,了解网络协议的运行机制和通信交互内容,以便进行问题排查和性能调优。要实现一个简易版Wireshark,需要实现以下基础功能: 1. 捕获网络数据包:通过网卡接口读取网络数据包,并将读到的数据包存储到内存中。 2. 分析网络数据包:对捕获的网络数据包进行解析,提取出关键信息,如源IP地址、目的IP地址、协议类型、端口号、消息内容等。 3. 显示网络数据包:将解析出的数据包信息以图形化的形式展示出来,便于用户观察和分析。 实现以上功能的关键是需要深入理解网络协议栈的原理和数据包格式。除此之外,还需要考虑到性能、容错性、数据存储等方面的问题。因此,实现简易版Wireshark需要具备较为扎实的网络和编程基础。可以使用Python、C++等语言来实现,通常需要结合网络库和图形化界面库进行开发。总的来说,实现简易版Wireshark需要投入较大的开发精力,但是可以提高网络层面的调试和分析能力。 ### 回答2: Wireshark是一款网络协议分析工具,它能够抓取网络数据包并进行分析。在大型网络环境中,Wireshark是非常有用的工具,它可以帮助网络管理员发现和解决各种网络问题。但是Wireshark功能非常强大,需要一定的技术知识才能使用。 如果想实现简易版Wireshark,可以遵循以下几个步骤: 首先,需要获取网络数据包,这可以通过套接字编程实现。使用套接字编程,可以访问网络接口并捕获数据包。可以编写函数来获取和处理捕获的数据包,并将其输出到控制台或文件中。 其次,需要学习和理解不同的网络协议。网络数据包可能包含多个协议,例如TCPUDP和IP。理解这些协议的结构和特性,可以解释捕获的数据包,帮助分析网络问题。 最后,需要开发用户界面,以让用户能够方便地使用该工具。控制台界面是一个不错的选择,因为它比较简单。也可以开发图形界面,增加更多的功能和可视化效果。 总之,简易版Wireshark可以通过套接字编程实现数据包捕获,理解网络协议并开发用户界面。这个过程需要一定的技术知识和开发经验,但是它可以帮助了解网络的基本功能,并发现一些网络问题。 ### 回答3: 实现简易版wireshark的关键在于抓包和解析包两个方面。抓包需要使用socket库,通过创建一个原始套接字,能够让我们直接访问网络层和传输层的数据。解析包则需要对捕获的数据进行处理,包括解析以太网帧、IPv4/IPv6报文、TCP/UDP协议等等。 这里我们提供一个简单实现的思路: 1. 使用socket库创建原始套接字,并且使用ioctl函数设置混杂模式,以接收所有经过网卡的数据包。 2. 对于每个捕获到的帧,利用C语言中的结构体按照协议层次封装成数据包。 3. 解析数据包的实现需要根据数据包的类型来选择不同的函数进行解析。例如,处理以太网帧时,需要按照以太网协议的格式进行解析,获取源地址、目的地址和协议类型等。而处理TCP协议时,则需要解析TCP首部长度、标志位、源端口、目的端口、序号、确认号等等。 4. 输出解析后的数据,并且可以将数据存储到文件中,方便我们进行后续的分析。 需要注意的是,虽然这个简易版wireshark能够捕获网络上的数据包并解析出各个协议层的信息,但是由于性能和可靠性的问题,不能够取代正式的wireshark软件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值