TCP、UDP、ICMP协议抓包详解

这里使用tcpdump对TCP、UDP、ICMP协议进行抓包,并详细解析其内容

1.实验源码

TCP和UDP抓包时使用以下tcp_echoserver.c、tcp_echoclient.c、udp_echoserver.c和udp_echoclient.c进行实验

tcp_echoserver.c

#include <arpa/inet.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

void str_echo(int sockfd) {
    char buf[1024];
    int n = 0;
    while ((n = read(sockfd, buf, 1024)) > 0) {
        write(sockfd, buf, n);
    }
}

int main(int argc, char **argv)
{
	int listenfd, connfd;
	struct sockaddr_in	servaddr;

	signal(SIGCHLD, SIG_IGN);

	listenfd = socket(AF_INET, SOCK_STREAM, 0);

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	inet_aton("127.0.0.1", &servaddr.sin_addr);
	servaddr.sin_port = htons(5001);

	bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
	listen(listenfd, 1024);
	
	for ( ; ; ) {
		connfd = accept(listenfd, NULL, NULL);

		if (fork() == 0) {      // child process
			close(listenfd);
			str_echo(connfd);
			exit(0);
		}

		close(connfd);      //father process close connection socket
	}
}

tcp_echoclient.c

#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

void str_client(FILE* fp, int sockfd) {
    char buf[1024], readline[1024];
    int n = 0;

    while (fgets(readline, 1024, fp) != NULL) {
        write(sockfd, readline, strlen(readline));
        if ((n = read(sockfd, buf, 1024)) <= 0)
            return;
        write(STDOUT_FILENO, buf, n);
    }
}

int main() {
    int sockfd;
    struct sockaddr_in servaddr;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    inet_aton("127.0.0.1", &servaddr.sin_addr);
    servaddr.sin_port = htons(5001);

    if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == 0) {
        str_client(stdin, sockfd);
    }
}

udp_echoserver.c

#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

#define BUF_SIZE 1024

int main(int argc, char **argv)
{
	int sockfd, n = 0;
	socklen_t addrlen;
	char buf[BUF_SIZE];
	struct sockaddr_in servaddr, cliaddr;

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(5002);

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
	
	for ( ; ; ) {
		addrlen = sizeof(cliaddr);
		n = recvfrom(sockfd, buf, BUF_SIZE, 0, &cliaddr, &addrlen);
		sendto(sockfd, buf, n, 0, &cliaddr, addrlen);
	}

	return 0;
}

udp_echoclient.c

#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

#define BUF_SIZE 1024

int main() {
    int sockfd;
	int n = 0;
    struct sockaddr_in servaddr;
	char buf[BUF_SIZE], readline[BUF_SIZE];
    
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
    servaddr.sin_port = htons(5002);

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    while (fgets(readline, BUF_SIZE, stdin) != NULL)
	{
		sendto(sockfd, readline, strlen(readline), 0, (struct sockaddr*)&servaddr, sizeof(servaddr));
		n = recvfrom(sockfd, buf, BUF_SIZE, 0, NULL, NULL);
        write(STDOUT_FILENO, buf, n);
    }
}

2.TCP数据包分析

在这里插入图片描述
这里的通信过程为:客户端连接到服务器,然后客户端输入AAAA并得到回射,最后客户端退出断开连接。这里一共捕获到十个IP数据报,其中前三个为TCP连接握手报文段,接下来的四个为数据传送报文段及数据确认报文段,最后三个为TCP断开握手报文段。

TCP三次握手及四次挥手

  TCP连接的建立在前三个报文段完成,第一个报文段为客户端发送到服务器的SYN报文段,其sequence字段为3466422460;第二个报文段为服务器发送到客户端的SYN+ACK报文段,其sequence字段为262482848,ack值为3466422461,表示对客户端SYN报文段的确认;最后客户端又向服务器发送了一个ACK报文段,其ack值为262482849,表示对上一个服务端数据包的确认。至此,TCP三次握手完成,服务端和客户端连接建立。
  TCP连接的断开在最后三个报文段完成,首先由于客户端进程退出,套接字作为进程资源清理的一部分会被操作系统关闭,由此触发客户端TCP协议栈进行连接断开的四次挥手。首先客户端向服务端发送一个FIN+ACK报文段,其sequence值为3466422466,ack值为262482854,从中可以看出是对服务端上一个数据报的确认;接下来服务端向客户端发送了一个FIN+ACK报文段,其sequence值为262482854,ack值为3466422467,对客户端的FIN报文段进行了确认同时发送了FIN报文段;最后客户端发送一个ACK报文段,其ack值为262482855,对服务端上一个报文段进行确认。至此,TCP断开四次挥手完成。

IP数据报分析

  对于IP数据报的具体含义,这里以第四个报文段(客户端向服务器发送数据)进行展开详述,从第一行可以看出客户端IP:端口、服务端IP:端口、数据报序号、上一个数据报确认号、客户端通告窗口、TCP数据长度(4个A加1个回车符)等信息。这里抓取到的是IP数据报,数据报总长度为71字节( [0x00~0x39) ),其中前20字节( [0x00~0x14) )为IP首部,后面51字节为TCP数据报。
数值 IP字段 释义

数值IP字段释义
0x54位头部长度(4字节)IP头部长度为5个4字节(20字节)
0x008位服务类型为应用层提供不同优先服务,例如ssh和telnet需要最小时延服务
0x003916位总长度(字节数)这个IP数据报长度为71字节
0x6e7316位标识用于唯一标识一个IP数据报,可用于IP分片与重组等(注意它和TCP序号值没有任何关系)
0x40003位标志+13位片偏移0x4000=010 0000000000000b,这个IP数据报不允许分片、后面没有更多分片、当前数据报片偏移为0
0x408位生存时间这个IP数据报在网络上最多可经过100跳
0x068位协议用于区分上层协议(如ICMP为1,TCP为6,UDP为17),将IP数据报的数据部分交付到不同的上层协议栈
0xce4916位首部校验和(注意这里只校验IP首部)
0x7f 00 00 0132位源IP地址源IP地址为127.0.0.1
0x7f 00 00 0132位目的IP地址目的IP地址为127.0.0.1

TCP数据报分析

数值TCP字段释义
0x831a16位源端口号源端口号为33562
0x138916位目的端口号目的端口号为5001
0xce9d 68bd32位序号此传输方向上的此TCP报文段的序号为3466422461
0x0fa5 2ba132位确认号期待收到对等端编号为262482849的下一个报文段
0x84位头部长度(4字节)TCP头部长度为32字节(有12字节的选项字段)
0x0 186位保留位+6位标志位0x018=0000 0001 1000b,后6位对应为URG,ACK,PSH,PST,SYN,FIN,即ACK和PSH被置位
0x020016位窗口大小本端通告窗口大小位512字节
0xfe2d16位校验和(注意这里对TCP首部和数据都进行校验)
0x000016位紧急指针
0x0101 080a 0a98 3852 0a97 ea2aTCP头部选项字段
0x4141 4141用户数据4个A
0x0a用户数据换行符

3.UDP数据包分析

在这里插入图片描述
同样的通信过程,可以看到UDP协议传输只有两次报文交换。

这里前20字节仍然是IP首部,因此不再赘述,只对UDP数据报部分进行分析,不过需要说明的是,这里IP首部的8位协议字段变为了0x11即十进制的17,表示IP协议的上层协议为UDP协议。

数值UDP字段释义
0x88ae16位源端口号源端口号为34990
0x138a16位目的端口号目的端口号为5002
0x000d16位UDP数据报长度此UDP数据报长度为13
0xfe2016位校验和
0x4142 4344用户数据ABCD
0x0a用户数据换行符

4.ICMP数据包分析

在这里插入图片描述
这里前20字节仍为IP首部,可以看到IP首部的8位协议字段变为了0x01,表示IP协议的上层协议为ICMP协议。

数值UDP字段释义
0x088位ICMP类型ICMP报文类型为echo回送服务
0x008位代码字段
0xf81516位校验和
0x1434 0001取决于报文类型
其余为选项部分+数据部分
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页