Java抓包分析三(基于jnetpcap进行抓包)——抓取Http请求数据包


本文主要分为三个阶段来进行展开

1.http请求建立的过程
2.使用wireshark对http请求进行抓包分析
3.使用jnetpcap对http请求进行抓包分析

对于一大堆协议来说,可能让我们最熟悉的协议就是http请求了,我相信只要是个程序员可能都接触过,通过restful这种方式调用别人的接口。
在浏览中,我们调用后端接口的时候,我们通常都会在开发者模式下进行调试,然后可以看到如下这些数据,现在嗯,我们对一个http请求接口做一个抓包分析。
在这里插入图片描述

1.http请求过程

首先来个开胃菜,一个在八股文中已经被背烂透的题,“从浏览器地址栏输入url到页面呈现的过程”
这里我就不过多的介绍了,主要过程有这么几个:
1.从DNS中得到链接ip地址
2.TCP连接,三次握手
3.数据请求(http请求)阶段
4.浏览器处理页面响应阶段
5.断开连接,TCP四次挥手
具体各个过程做什么,我们这里不做具体分析介绍,现在我们做一个抓包分析过程,我们参照上面的流程开始我们的抓包工作,只不过,这里我们不是访问url页面,而是访问rest接口。

1.1.准备工作

一台电脑提供rest接口(或者其他服务提供的rest接口),一个get请求接口,一个post请求接口。
其中我们的抓包程序在B电脑上,并且由B像A发送请求,切记不可B向B发送请求,因为在前面两个章节学习中,我们知道,我们是通过网卡去捕获数据包的,如果你自己请求自己,都不走网卡了,肯定是捕获不到数据包的。
在这里插入图片描述

1.2.http请求流程示意图

通过如下图所示,在我们进行http请求建立的时候,首先需要通过TCP三次握手来建立建立TCP连接,然后http在TCP连接的基础上进行HTTP连接,最后在通过TCP四次挥手来释放TCP连接。当然,实际效果可能和咱们这个流程图由差异。具体参见http keep-alive,我们接下来的案例中也会提到。
在这里插入图片描述
如下三次握手,四次挥手参考如下这个哥们,写的挺好的,这里我就不重复啰嗦了,就复制粘贴过来了。
详解 TCP 连接的“ 三次握手 ”与“ 四次挥手 ”
如果你嫌弃下面篇幅太多,理解不过来,最起码你要记得上图中三次握手,四次握手中都传了什么参数,每个参数代表什么含义,因为我们要在抓包中,去看这些参数,不过建议你看是认真看完,毕竟网络中TCP三次握手,面试笔试还是挺高频的。这也是我们研究http的基础。

1.3三/四次握手

由于TCP不存在连接的概念,只存在请求和响应,请求和响应都是数据包,它们之间都是经过由TCP创建的一个从客户端发起,服务器接收的类似连接的通道,这个连接可以一直保持,http请求是在这个连接的基础上发送的;
在一个TCP连接上是可以发送多个http请求的,不同的版本这个模式不一样。
在HTTP/1.0中这个TCP连接是在http请求创建的时候同步创建的,http请求发送到服务器端,服务器端响应了之后,这个TCP连接就关闭了;
HTTP/1.1中可以以某种方式声明这个连接一直保持,一个请求传输完之后,另一个请求可以接着传输。这样的好处是:在创建一个TCP连接的过程中需要“三次握手”的消耗,“三次握手”代表有三次网络传输。
如果TCP连接保持,第二个请求发送就没有这“三次握手”的消耗。HTTP/2中同一个TCP连接里还可以并发地传输http请求。

1.3.1.Seq序号/确认号Ack/标志位Flags

(1)序号(sequence number):Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。
(2)确认号(acknowledgement number):Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。
(3)标志位(Flags):共6个,即URG、ACK、PSH、RST、SYN、FIN等。具体含义如下:

符号含义
URG紧急指针(urgent pointer)有效
ACK确认序号有效
PSH接收方应该尽快将这个报文交给应用层
RST重置连接
SYN发起一个新连接
FIN释放一个连接

需要注意的是:
不要将确认序号Ack与标志位中的ACK搞混了。确认方Ack=发起方Seq+1,两端配对。

1.3.2.三次握手流程

所谓的三次握手即TCP连接的建立。这个连接必须是一方主动打开,另一方被动打开的。以下为客户端主动发起连接的图解。
在这里插入图片描述
(1)首先客户端向服务器端发送一段TCP报文。

  1. 标记位为SYN,表示“请求建立新连接”;
  2. 序号为Seq=x(x一般为0);
  3. 随后客户端进入SYN-SENT阶段。

(2)服务器端接收到来自客户端的TCP报文之后,结束LISTEN阶段。并返回一段TCP报文

  1. 标志位为SYN和ACK,表示“确认客户端的报文Seq序号有效,服务器能正常接收客户端发送的数据,并同意创建新连接”(即告诉客户端,服务器收到了你的数据);
  2. 序号为Seq=y(y一般为0);
  3. 确认号为Ack=x+1,表示收到客户端的序号Seq并将其值加1作为自己确认号Ack的值;随后服务器端进入SYN-RCVD阶段。

(3)客户端接收到来自服务器端的确认收到数据的TCP报文之后,明确了从客户端到服务器的数据传输是正常的,结束SYN-SENT阶段。并返回最后一段TCP报文。

  1. 标志位为ACK,表示“确认收到服务器端同意连接的信号”(即告诉服务器,我知道你收到我发的数据了);
  2. 序号为Seq=x+1,表示收到服务器端的确认号Ack,并将其值作为自己的序号值;
  3. 确认号为Ack=y+1,表示收到服务器端序号Seq,并将其值加1作为自己的确认号Ack的值;
  4. 随后客户端进入ESTABLISHED阶段。服务器收到来自客户端的“确认收到服务器数据”的TCP报文之后,明确了从服务器到客户端的数据传输是正常的。结束SYN-SENT阶段,进入ESTABLISHED阶段。

在客户端与服务器端传输的TCP报文中,双方的确认号Ack和序号Seq的值,都是在彼此Ack和Seq值的基础上进行计算的,这样做保证了TCP报文传输的连贯性。一旦出现某一方发出的TCP报文丢失,便无法继续"握手",以此确保了"三次握手"的顺利完成。

1.3.3.四次挥手流程

所谓的四次挥手即TCP连接的释放(解除)。连接的释放必须是一方主动释放,另一方被动释放。以下为客户端主动发起释放连接的图解
在这里插入图片描述
(1)首先客户端想要释放连接,向服务器端发送一段TCP报文。

  1. 标记位为FIN,表示“请求释放连接“;
  2. 序号为Seq=U;
  3. 随后客户端进入FIN-WAIT-1阶段,即半关闭阶段。并且停止在客户端到服务器端方向上发送数据,但是客户端仍然能接收从服务器端传输过来的数据。
    注意:这里不发送的是正常连接时传输的数据(非确认报文),而不是一切数据,所以客户端仍然能发送ACK确认报文。

(2)服务器端接收到从客户端发出的TCP报文之后,确认了客户端想要释放连接,随后服务器端结束ESTABLISHED阶段,进入CLOSE-WAIT阶段(半关闭状态)并返回一段TCP报文。

  1. 标记位为ACK,表示“接收到客户端发送的释放连接的请求”;
  2. 序号为Seq=V;
  3. 确认号为Ack=U+1,表示是在收到客户端报文的基础上,将其序号Seq值加1作为本段报文确认号Ack的值;
  4. 随后服务器端开始准备释放服务器端到客户端方向上的连接。
    客户端收到从服务器端发出的TCP报文之后,确认了服务器收到了客户端发出的释放连接请求,随后客户端结束FIN-WAIT-1阶段,进入FIN-WAIT-2阶段

前"两次挥手"既让服务器端知道了客户端想要释放连接,也让客户端知道了服务器端了解了自己想要释放连接的请求。于是,可以确认关闭客户端到服务器端方向上的连接了

(3)服务器端自从发出ACK确认报文之后,经过CLOSED-WAIT阶段,做好了释放服务器端到客户端方向上的连接准备,再次向客户端发出一段TCP报文

  1. 标记位为FIN,ACK,表示“已经准备好释放连接了”。注意:这里的ACK并不是确认收到服务器端报文的确认报文。
  2. 序号为Seq=W;
  3. 确认号为Ack=U+1;表示是在收到客户端报文的基础上,将其序号Seq值加1作为本段报文确认号Ack的值。
  4. 随后服务器端结束CLOSE-WAIT阶段,进入LAST-ACK阶段。并且停止在服务器端到客户端的方向上发送数据,但是服务器端仍然能够接收从客户端传输过来的数据。

(4)客户端收到从服务器端发出的TCP报文,确认了服务器端已做好释放连接的准备,结束FIN-WAIT-2阶段,进入TIME-WAIT阶段,并向服务器端发送一段报文。

  1. 标记位为ACK,表示“接收到服务器准备好释放连接的信号”。
  2. 序号为Seq=U+1;表示是在收到了服务器端报文的基础上,将其确认号Ack值作为本段报文序号的值。
  3. 确认号为Ack=W+1;表示是在收到了服务器端报文的基础上,将其序号Seq值作为本段报文确认号的值。

2.使用wireshark对http请求进行抓包分析

2.1.准备工作

机器A准备服务接口这里我们接口访问地址准备为
192.168.1.27:8085/test/post,在这个接口中,我们将客户端请求的参数返回。
机器B地址为:192.168.1.233

这是我们使用postman进行调用的一个示例
在这里插入图片描述
确保接口可用之后,我们接下来使用wireshark进行抓包

2.2.wireshark安装

下载地址https://wireshark.en.softonic.com/
无脑下一步安装就可以了,然后为了避免其他的问题,或者找不到网卡等问题,建议以管理员方式启动(我的电脑就是需要管理员方式启动,不然找不到网卡)

2.3.wireshark的简单使用

分别点击捕获——》选项——》
在这里插入图片描述
这里我们使用混杂模式,点击开始进行抓包分析(当然你也可以什么都不做配置,用默认的直接开始也可以)
在这里插入图片描述
这是后我们就可以看到下面不停的进行抓包操作,点击左上角红色正方型,即可停止抓包。
在这里插入图片描述
点击蓝色鲨鱼背鳍开始抓包
在这里插入图片描述

2.4.wireshark抓取http请求数据包过程

准备工作
在我们准备过程中
192.168.1.233是客户端
192.168.1.27是服务端

  1. 点击开始抓包
    在这里插入图片描述

  2. 使用postman或者其他工具发起http请求
    在这里插入图片描述

  3. 停止抓包
    在这里插入图片描述

  4. 条件过滤
    在 wireshark中,我们的过滤条件就可以设置为
    发送方是192.168.1.233,并且接受方是192.168.1.27(客户端和服务端通信)
    或者
    发送方是192.168.1.27 ,并且接受方是192.168.1.233 (服务段和客户端通信)
    (如果你自己测试,则将客户端和服务端的IP地址修改为你自己的)

(ip.src==192.168.1.233 and ip.dst==192.168.1.27) or (ip.src==192.168.1.27 and ip.dst==192.168.1.233)

通过条件过滤后,我们就特别显眼的看到了三次握手建立TCP之后,发起了http请求。
在这里插入图片描述

2.5.分析wireshark抓取数据包

2.5.1.三次握手示例图

在这里插入图片描述
在这里插入图片描述

2.5.2.第一次握手

客户端(233)向服务端(27)发送[SYN]和Seq

  1. 标记位为SYN,表示“请求建立新连接”;
  2. 序号为Seq=x(x一般为0);
  3. 随后客户端进入SYN-SENT阶段。
    在这里插入图片描述

2.5.3.第二次握手

服务端(27)向服务端(233)发送[SYN、ACK]、Seq、Ack

  1. 标志位为SYN和ACK,表示“确认客户端的报文Seq序号有效,服务器能正常接收客户端发送的数据,并同意创建新连接”(即告诉客户端,服务器收到了你的数据);
  2. 序号为Seq=y(y一般为0);
  3. 确认号为Ack=x+1,表示收到客户端的序号Seq并将其值加1作为自己确认号Ack的值;随后服务器端进入SYN-RCVD阶段。
    在这里插入图片描述

2.5.4.第三次握手

客户端(233)向服务端(27)发送[ACK]、Seq、Ack

  1. 标志位为ACK,表示“确认收到服务器端同意连接的信号”(即告诉服务器,我知道你收到我发的数据了);
  2. 序号为Seq=x+1,表示收到服务器端的确认号Ack,并将其值作为自己的序号值;
  3. 确认号为Ack=y+1,表示收到服务器端序号Seq,并将其值加1作为自己的确认号Ack的值;
  4. 随后客户端进入ESTABLISHED阶段。服务器收到来自客户端的“确认收到服务器数据”的TCP报文之后,明确了从服务器到客户端的数据传输是正常的。结束SYN-SENT阶段,进入ESTABLISHED阶段。
    在这里插入图片描述

2.5.5. 客户端http请求服务端

我们可以从我们抓包中的过程中直接发现第三次TCP握手之后,接着就是http请求了(这里的抓包和我上边的不是同一个请求的抓包,所以时间戳有差异,不过流程都是一样的),并且是从客户端向服务端发起的请求,从这个http请求中我们可以看到我们的请求参数,当然你看到的这个请求参数是经过wireshark处理过的,不然我们看到的就是左下角的那堆16进制的数字了。
在这里插入图片描述

2.5.6. 服务端http请求客户端

我们可以看到,在客户端向服务端发起Http请求后,服务端并没有直接就向客户端发送Http请求,而是先发送了一个TCP Window Update和TCP[ACK]之后,服务端才向客户端发送http请求,去响应和客户端的请求。
Tcp window update(tcp窗口更新)

CP窗口更新。
当接收方的TCP window发生突变时,接收方通过TCP window update消息告知对方当前的接收窗口大小。如下图,TCP window Update同时携带了反馈ack,ack序列号与前一个反馈ack序列号相同,但这并不是重复ack。
tcp window update是TCP通信中的一个状态,它可以发生的原因有很多,但最终归结于发送者传输数据的速度比接收者读取的数据还快,这使得接受端的在缓冲区必须释放一部分空间来装发送过来的数据,然后向发送者发送Windows Update,告诉给发送者应该以多大的速度发送数据,从而使得数据传输与接受恢复正常。
在这里插入图片描述
至此,我们使用wireshark对Http请求的一个过程大致了解就差不多了。
后续还有一个TCP四次挥手,流程可以对照三次握手,本文就不在继续深究具体可以参照这个哥们所写
https://www.cnblogs.com/wei57960/p/12180382.html

3.使用jnetpcap对http请求进行抓包

接下来,让我们用一个简单的jnetpcap代码示例来对我们的Http进行抓包
这块我们沿用之前写的快速入门案例
Java抓包分析二(基于jnetpcap进行抓包)——快速入门案例
主要对CustomPcapHandler做些处理,其他不变。

3.1.CaptureUtils

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import org.jnetpcap.Pcap;
import org.jnetpcap.PcapIf;
import com.capture.hutao.packetHandler.CustomPcapHandler;

/**
 * @Description:抓包工具类
 * @author:hutao
 * @mail:hutao_2017@aliyun.com
 * @date:2021年9月2日
 */
public class CaptureUtils {
	
	/**
	 * @Description:获取网络适配器,当返回List<PcapIf>为空时,说明未获取到网卡
	 * @author:hutao
	 * @mail:hutao_2017@aliyun.com
	 * @date:2021年9月2日
	 */
	public static List<PcapIf> getPcapIf() {
		StringBuilder errbuf = new StringBuilder();
		//定义网卡列表
		List<PcapIf> ifs = new ArrayList<PcapIf>(); 
		/* 返回值是一个整数结果代码,就像在 C 计数器部分一样。
		 * ifs 列表中填充了从 C 函数调用 findAllDevs 返回的相应 C 结构 pcap_if 链表中找到的所有网络设备。
		 */
		int statusCode = Pcap.findAllDevs(ifs, errbuf);
		if(statusCode != Pcap.OK){
			System.err.println("获取网卡失败:" + errbuf.toString());
		}
		return ifs;
    }
	
	/**
	 * @Description:开始捕获数据包
	 * @param
	 * @author:hutao
	 * @mail:hutao_2017@aliyun.com
	 * @date:2021年9月2日
	 */
	public static void capturePcap(PcapIf device) {
		//截断此大小的数据包
		int snaplen = Pcap.DEFAULT_JPACKET_BUFFER_SIZE;
		
		int promiscous = Pcap.MODE_PROMISCUOUS;
		
		//以毫秒为单位
		int timeout = 60 * 1000; 
		//如果发生错误,它将保存一个错误字符串。 错误打开 Live 将返回 null
		StringBuilder errbuf = new StringBuilder();
		
		Pcap pcap = Pcap.openLive(device.getName(),snaplen,promiscous,timeout,errbuf);
		if(pcap == null) {
			System.err.println("获取数据包失败:" + errbuf.toString());
		}
		
		CustomPcapHandler<Object> handler = new CustomPcapHandler<Object>();
		// 捕获数据包计数
		int cnt = 1;
		//我们要发送到处理程序的自定义对象
		PrintStream out = System.out;
		while(true) {
			//每个数据包将被分派到抓包处理器Handler
			pcap.loop(cnt, handler, out);
		}
		//pcap.close();
	}
}

3.2.DemoTest

import java.util.List;
import org.jnetpcap.PcapIf;
import com.capture.hutao.utils.CaptureUtils;

public class DemoTest {
	public static void main(String[] args) {
		List<PcapIf> networkAdapter = CaptureUtils.getPcapIf();
		CaptureUtils.capturePcap(networkAdapter.get(0));
	}
}

3.3.CustomPcapHandler

import org.jnetpcap.packet.PcapPacket;
import org.jnetpcap.packet.PcapPacketHandler;
import org.jnetpcap.protocol.tcpip.Http;
public class CustomPcapHandler<Object> implements PcapPacketHandler<Object>{
	private Http http = new Http();
	@Override
	public void nextPacket(PcapPacket packet, Object user) {
		//抓取的包协议是Http
		if (packet.hasHeader(http)) {
			System.out.println(packet);
		}
	}
}

客户端(223)向服务端(27)发送请求
在这里插入图片描述
服务端(27)向客户端(223)发送请求
在这里插入图片描述
至此Java基于(基于jnetpcap进行抓包)——抓取Http请求数据包完毕,当然,这里面问题还有很多,比如乱码等,如何解析这些问题,我们下章节在依次深入,本章节只是先做一件事,如何抓包。至于如何分析,咱还需要有很多事需要做。

  • 11
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值