linux上使用tcpdump工具抓包(基于TCP协议的客户端向服务端发送信息,以及使用SSL/TLS协议之后客户端向服务端发送信息)和wireshark工具分析抓包(linux/C/C++)

视频讲解:https://www.bilibili.com/video/BV1axtXzWEX6?spm_id_from=333.788.videopod.sections&vd_source=b2eaaddb2c69bf42517a2553af8444ab

目录

代码编译

Linux上基于tcpdump抓包

tcpdump抓包命令

tcpdump抓包参数解析

抓包流程

wireshark抓包分析

单纯基于TCP协议传输数据过程

TCP协议 + SSL/TLS(安全套接层)协议

OpenSSL库

​​编程接口(API)​​

自签证书和正式证书有什么区别呢

私钥和证书(自签证书)生成命令

验证密钥与证书是否匹配

如果要加密私钥的话

抓包结果

参考链接


代码下载地址:https://github.com/KeepTryingTo/openssl-client-server-WireShark

        基于TCP协议的socket网络编程大家应该是比较熟悉的了,特别是大家在学习网络编程或者web,http服务相关项目时,这个是必须要知道的,关于基于epoll的IO多路复用大家也应该尝试去了解一下,为什么要使用epoll机制。今天这个文章内容对于很多人来说都是非常熟悉的,所以应该没有什么问题,主要在linux上基于tcpdump工具抓取客户端向服务端发送数据的过程以及到tcp最后挥手,主要有两种测试方式,一种是单纯基于TCP协议传输数据,另外一种是基于TCP和SSL/TLS协议加密传输数据的过程,通过抓包来看一下整个过程,并且还给出了怎么生成私钥以及证书。

代码编译

cd simple_cli_ser
make

cd bin
./server #启动服务端
./client #启动客户端

Linux上基于tcpdump抓包

tcpdump抓包命令
sudo tcpdump -i any -w tcp.pcap -v host 127.0.0.1 and port 8080 and tcp #本项目使用的这一条就可以了

# 同时显示抓包信息到控制台
sudo tcpdump -i any -w tcp.pcap -v host 127.0.0.1 and port 8080 and tcp

# 限制抓包数量(例如只抓100个包)
sudo tcpdump -i any -w tcp.pcap -c 100 host 127.0.0.1 and port 8080 and tcp

# 指定网络接口(如只监控回环接口)
sudo tcpdump -i lo -w tcp.pcap host 127.0.0.1 and port 8080 and tcp
tcpdump抓包参数解析

参数/表达式

说明

sudo

需要管理员权限才能捕获网络数据包

tcpdump

抓包工具命令

-i any

监听所有网络接口(包括lo回环接口)

-w tcp.pcap

将抓包数据保存到 tcp.pcap 文件中

host 127.0.0.1

过滤主机IP为127.0.0.1(本地回环)

port 8080

过滤端口为8080

tcp

只捕获TCP协议的数据包

-v

显示抓包信息到控制台

-c 100

指定只抓100个包

-i lo

指定网络接口(只监控回环接口)

抓包流程

  • 开启第一个终端:首先启动服务器,比如./server
  • 开启第二个终端:其次输入tcpdump抓包命令
  • 开启第三个终端:最后启动客户端,比如./client

wireshark抓包分析

  • SYN 表示建立连接,
  • FIN 表示关闭连接,
  • ACK 表示响应,
  • PSH 表示有 DATA 数据传输,
  • RST 表示连接重置。
单纯基于TCP协议传输数据过程

注意:

从TCP三次握手,然后进行数据传输以及ACK确认,到最后的TCP四次挥手合并为三次挥手(TCP延迟确认机制开启),这个整个过程就是一个典型的TCP连接到数据传输以及断开连接的过程。

大家看到的上面TCP握手过程的序列号是从0开始的,这只是因为wireshark工具使用相对序列号进行表示的,因此,在消息栏右击 → 协议首选项 → Transmission Control Protocol → 点击Relative sequence numbers ...就可以看到绝对的序列号了。 其实使用相对序列号也可以,并不妨碍我们观察 。

注:从抓包的内容来看,确实是首相客户端向服务端发送hello,server消息之后,其次服务端向客户端会送消息hello,server,由于是基于TCP数据传输,整个过程都是明文传输。

TCP协议 + SSL/TLS(安全套接层)协议
OpenSSL库

OpenSSL​​ 是一个功能完备的、商业级的、开源的工具包,实现了 ​​SSL(Secure Sockets Layer)​​ 和 ​​TLS(Transport Layer Security)​​ 协议。它提供了一个强大的通用密码学库,用于保护网络通信的安全。

OpenSSL 项目主要包含三个核心组件:

​1. libcrypto- 密码学库​​ 这是 OpenSSL 的基础和灵魂。它是一个提供各种加密、解密、哈希、数字签名等底层操作的通用密码学库。

  • 对称加密​​:AES, DES, 3DES, Blowfish, ChaCha20 等。
  • 非对称加密(公钥加密)​​:RSA, DSA, Diffie-Hellman, EC(椭圆曲线)等。
  • ​哈希函数​​:MD5, SHA-1, SHA-256, SHA-3 等。
  • ​数字证书​​:X.509 证书的编码、解码和管理。
  • 随机数生成​​:提供加密安全的伪随机数生成器(CSPRNG)。
  • 编码转换​​:支持 ASN.1, PEM, DER 等格式的编解码。

​2. libssl- SSL/TLS 协议库​ 这个库建立在 libcrypto之上,实现了 SSL 和 TLS 协议。它提供了客户端和服务器端的 API,用于创建安全的加密通信通道。

  • 处理复杂的​​握手过程​​(密钥交换、身份验证)。
  • 建立连接后的​​应用数据加密传输​​。
  • 提供高级别的 API(如 SSL_readSSL_write),让开发者无需深入理解密码学细节也能轻松实现安全通信。

​3. openssl- 命令行工具​​ 这是一个极其强大的多功能命令行工具,可以单独使用,无需编程。

  • ​生成密钥和证书​​:openssl genrsaopenssl req
  • 模拟客户端/服务器​​:openssl s_clientopenssl s_server
  • 数据加密解密​​:openssl enc
  • 计算哈希值​​:openssl dgst
  • 诊断和调试​​:检查证书、测试连接等。

​编程接口(API)​

 OpenSSL 通常书写步骤:

  1. 初始化库​​:SSL_library_init()
  2. 创建上下文(CTX)​​:SSL_CTX_new(),用于存储全局设置和证书。
  3. 绑定 socket​​:将网络 socket 与 SSL 结构关联。
  4. ​执行 SSL/TLS 握手​​:SSL_connect()(客户端) 或 SSL_accept()(服务器)。
  5. ​安全通信​​:使用 SSL_read()和 SSL_write()替代普通的 read()和 write()
  6. 清理​​:关闭连接并释放资源。

自签证书和正式证书有什么区别呢

特性​

​自签证书​

​正式证书(CA签发)​

​签发机构​

自己签发

受信任的证书颁发机构(CA)如 Let's Encrypt、DigiCert

​信任链​

无第三方背书,需手动信任

自动嵌入浏览器/操作系统的信任链

​加密强度​

与正式证书相同(取决于密钥算法和长度)

与自签证书相同

​浏览器警告​

显示"不安全"警告

显示绿色锁标志(EV证书显示公司名称)

​有效期​

可自定义(通常较长)

通常较短(如90天~1年)

​适用场景​

内部测试、开发环境、内网服务

公网网站、商业服务、API接口

私钥和证书(自签证书)生成命令
# 生成私钥(保存为 .pem 格式)
openssl genrsa -out server.pem 2048

# 生成自签名证书(保存为 .pem 格式)
openssl req -new -x509 -sha256 -key server.pem -out cert.pem -days 3650

# 查看证书信息(包含了签名算法,生成证书时填写的信息等)
openssl x509 -in cert.pem -noout -text

openssl genrsa -out server.pem 2048

参数

说明

genrsa

生成RSA私钥

-out server.pem

指定输出文件为server.pem

2048

密钥长度(位),推荐2048或4096

openssl req -new -x509 -sha256 -key server.pem -out cert.pem -days 3650

参数

说明

req

证书请求和生成命令

-new

创建新证书请求

-x509

生成自签名证书(而非证书请求)

-sha256

使用SHA-256哈希算法

-key server.pem

指定使用的私钥文件

-out cert.pem

输出证书文件

-days 3650

证书有效期(10年)

openssl x509 -in cert.pem -noout -text

参数

说明

x509

处理X.509证书

-in cert.pem

指定输入证书文件

-noout

不输出证书本身(只输出解析信息)

-text

以可读格式显示完整证书信息

验证密钥与证书是否匹配
验证密钥与证书是否匹配
openssl x509 -noout -modulus -in cert.pem | openssl md5
输出:(stdin)= 8b92476c6177fff45071d3c55b67b54b
openssl rsa -noout -modulus -in server.pem | openssl md5
输出:(stdin)= 8b92476c6177fff45071d3c55b67b54b

如果要加密私钥的话
命令:openssl genrsa -aes256 -out server.pem 2048
提示:
Enter pass phrase for server.pem:  [输入密码]
Verifying - Enter pass phrase for server.pem:  [确认密码]


验证加密
命令:file server.pem  # 会显示"PEM RSA private key"
命令:openssl rsa -in server.pem -check  # 会提示输入密码

移除私钥密码
openssl rsa -in server.pem -out server_unencrypted.pem

参数

作用

-aes256

使用AES-256算法加密私钥(推荐)

-out server.pem

输出加密后的私钥文件

2048

RSA密钥长度(位)

其他加密算法:-des3,-camellia256

抓包结果

注:首先进行三次握手,其次是SSL/TLS四次握手,后面是发送,最后是断开连接

大家可能看到上面在最后客户端向服务端发送了RST报文,说明异常终止了,需要再客户端最后更新如下代码:

分析原因:从抓包图可以清晰地看到问题所在:

  1. No.15​​: 服务端发送了最后的 Application Data
  2. No.16​​: 客户端发送 [FIN, ACK],表示"我的数据已发完,想要关闭连接"
  3. No.17​​: 但服务端的 while循环中的 SSL_write又尝试发送数据
  4. No.18​​: 客户端已经准备关闭连接,收到"意外"数据,只能发送 [RST]强制重置

根源在于服务端的这段代码:当服务端接收来自客户端的数据之后,马上回显,但是客户端那边已经关闭,导致最终客户端发送RST报文来强制断开连接。

/* 处理客户端数据 */
int bytes_received;
while ((bytes_received = SSL_read(ssl, buffer, BUFFER_SIZE)) > 0)
{
    buffer[bytes_received] = '\0';
    printf("Received: %s\n", buffer);

    /* 回显数据 */
    SSL_write(ssl, buffer, bytes_received);
}

修改后的代码:

// 只读取数据,不立即回显
bytes_received = SSL_read(ssl, complete_buffer, sizeof(complete_buffer));
complete_buffer[bytes_received] = '\0';
printf("recv data: %s\n", complete_buffer);

// 读取完成后,一次性回显所有数据
if (bytes_received > 0)
{
   printf("Complete message: %s\n", complete_buffer);
   SSL_write(ssl, complete_buffer, bytes_received);
   printf("Echoed %d bytes back to client\n", bytes_received);
   // 等待客户端关闭连接
   printf("Waiting for client to close connection...\n");
   while (SSL_read(ssl, buffer, BUFFER_SIZE) > 0)
   {
        // 空循环,等待客户端关闭(客户端那边接收完数据之后就会断开连接)
   }

   printf("Client closed connection\n");
}

注:第一次握手的信息,关于SSL/TLS协议的四次握手过程网上有很多讲解,这里就不过多的赘述了。

可以看到整个数据都是加密的,看不到具体发送了什么数据。

发送数据过程中会同时有PSH和 ACK两个标识?

答:这个组合 [PSH, ACK]理解为:​​“我这边有新的数据要立刻交给你(PSH),并且我也确认收到了你之前发来的数据(ACK)”,比如以上面传输数据为例子:

  1. No.4: 38008 → 8080 [PSH, ACK] Seq=1 Ack=1 Win=65536 Len=283
    • [PSH]​:客户端(38008端口)告诉服务器(8080端口):“我这里有283字节的应用数据(比如一个HTTP请求),请立即处理”。

    • [ACK]​:客户端同时告诉服务器:“你之前发来的所有数据(比如握手阶段的包)我都收到了,一切正常。我下一个期望收到的序列号是 Ack=1”。

  2. No.6: 8080 → 38008 [PSH, ACK] Seq=1 Ack=284 Win=65536 Len=1421
    • [PSH]​:服务器处理完客户端的请求后,生成了1421字节的响应数据(比如一个HTTP响应),并立即推送回去。

    • [ACK]​:服务器同时告诉客户端:“你之前发来的283字节数据我已经收到了,下一个期望收到的序列号是 Ack=284(即 Seq=1 + Len=283)”。

TCP协议这样设计,主要是为了​​效率和可靠性​​的极致结合:

  1. 减少报文数量(捎带确认 - Piggybacking)​​:
    • 理论上,发送数据和确认收到数据可以是两个独立的TCP包。
    • 但这样效率太低。如果一方正好有数据要发送 (PSH),而它又需要确认对方之前发来的数据 (ACK),那么完全可以将这两个信息合并到一个包里发送。这大大减少了网络上的报文数量,提升了效率。
  2. 及时交付与流量控制​​:
    • PSH标志位就像一个“刷新”按钮。没有它,接收方的TCP栈可能会为了优化而暂时将数据缓存起来,等待凑够一个更大的数据块再提交给应用程序,这会引入延迟。
    • 对于交互式应用(如SSH、HTTP请求/响应),及时交付至关重要。PSH标志确保了低延迟,让应用程序能立刻对收到的数据做出反应。

想象两个人在用对讲机对话:

  • ​A​​:“Over.(我说完了)”(这就像 PSH,表示我有一段完整的信息给你)
  • ​B​​:“Roger that. I need backup!(收到。我需要支援!)”(这就像一个 [PSH, ACK]包。Roger that是 ACK,确认收到了A的话;I need backup!是 PSH,是B要发送的新信息)

参考链接

代码下载地址:https://github.com/yedf2/openssl-example

client-server代码来源:https://space.bilibili.com/193137215?spm_id_from=333.788.upinfo.head.click

关于抓包工具Wireshark使用:https://blog.youkuaiyun.com/qq_39720249/article/details/128157288

基于TCP的四次挥手调用shutdown和close函数区别:

https://blog.youkuaiyun.com/SteveForever/article/details/140638476

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值