ICMP协议报文

news2024/10/7 11:30:33

1、CMP协议简介


ICMP(Internet Control Message Protocol)是一种网络协议,它用于在IP网络中传递控制信息和错误消息。它通常与IP协议一起使用,IP协议负责发送和路由数据包,而ICMP协议负责检查网络是否可达、路由是否正确、主机是否可达等网络状态的反馈信息。

2、ICMP协议的主要功能

发现网络错误:当一个数据包在传输过程中出现错误时,ICMP协议通过向发送方发送错误通知来发现网络错误。

检查网络是否可达:通过发送ICMP ECHO请求并接收ICMP ECHO回复消息,可以确定目标主机是否可达。

发现主机错误:当一个主机无法正常工作时,ICMP协议通过向发送方发送错误通知来发现主机错误。

发送路由信息:ICMP协议可以向其他主机发送路由信息,以帮助它们在网络中找到合适的路由。


3、CMP报文格式


3.1、 ICMP报文以太网数据帧格式 

 ICMP报文属于IP子协议,协议号为1。

3.2、 ICMP首部格式

 

 

其中各字段的含义如下:

类型(Type):指定 ICMP 报文的类型,占 1 个字节。常见类型有:回显应答(Echo Reply:0)、回显请求(Echo Request:8)等。

代码(Code):指定 ICMP 报文的代码,占 1 个字节。用于进一步描述 ICMP 报文,与 Type 字段组合使用。

校验和(Checksum):校验和,用于检查 ICMP 报文是否有损坏,占 2 个字节。

由类型决定的4字节:根据类型不一样,4字节表达的意思不一样。

数据(Data):数据,可变长度。可以是任意数据,长度由具体的 ICMP 报文类型和代码决定。
 

3.3、 ICMP报文类型列表

 

常见的ICMP报文类型:

Echo Reply(回显应答):用于回复Echo Request(回显请求)报文,通常用于测试网络连接是否正常。

Destination Unreachable(目的地不可达):用于指示主机或路由器无法到达目的地或某个网络服务不可用。

Source Quench(源站抑制):当接收方无法处理所有传入的数据报时,源站抑制报文会发送到发送方,以通知其减慢数据传输速度。

Redirect(重定向):用于通知发送方,其正在使用的路由不再是最佳路由,建议使用另一条路由。

Echo Request(回显请求):用于测试测试网络连接是否正常。

Time Exceeded(时间超时):用于指示一个数据包在传输过程中被丢弃,原因是数据包在经过路由器时超过了其生存时间。

Parameter Problem(参数问题):用于指示数据包头部中存在错误的参数或选项,导致数据包无法被识别或处理。

Timestamp Request/Reply(时间戳请求/应答):用于向另一个主机请求当前时间戳,并将其返回给请求方。

Information Request/Reply(信息请求/应答):用于向另一个主机请求特定信息,并将其返回给请求方。

Address Mask Request/Reply(地址掩码请求/应答):用于请求另一个主机的网络掩码,并将其返回给请求方。

4、ICMP校验和计算


ICMP校验和计算的校验数据为整个ICMP数据包。

4.1 、ICMP校验和计算


a.校验数据以16bit为单位进行累加求和,校验数据需为偶数字节,奇数字节末尾填充0变为偶数字节。

b.如果累加和超过16bit,产生了进位,需将高16bit和低16bit累加求和。

c.循环步骤2,直至未产生进位为止。

d.累加和取反得到校验和。

4.2、 ICMP校验和验证


a.校验数据16bit为单位进行累加求和,校验数据需为偶数字节,奇数字节末尾填充0变为偶数字节。

b.如果累加和超过16bit,产生了进位,需将高16bit和低16bit累加求和。

c.循环步骤2,直至未产生进位为止。

d.累加和和校验和相加得到0xffff,校验成功,否则失败。


5、ICMP编程示例

5.1、发送回显请求

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <arpa/inet.h>
 
#define PACKET_SIZE 4096
#define ICMP_PACKET_SIZE 28
 
uint16_t checksum(uint16_t *buf, int len)
{
    unsigned long sum = 0;
    while (len > 1) {
        sum += *buf++;
        len -= 2;
    }
    if (len == 1) {
        sum += *(unsigned char *)buf;
    }
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    return ~sum;
}
 
int main(int argc, char *argv[])
{
    if (argc != 2) {
        printf("Usage: %s <destination_ip>\n", argv[0]);
        return -1;
    }
 
    char buf[PACKET_SIZE] = {0};
    memset(buf, 0, sizeof(buf));
 
    int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (sockfd < 0) {
        perror("socket error");
        return -1;
    }
 
    struct sockaddr_in dest_addr;
    memset(&dest_addr, 0, sizeof(dest_addr));
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_addr.s_addr = inet_addr(argv[1]);
 
    uint16_t seq = 0;
    while(1) {
        memset(buf, 0, PACKET_SIZE);
        struct icmp *icmp_packet = (struct icmp *)buf;
        icmp_packet->icmp_type = ICMP_ECHO;
        icmp_packet->icmp_code = 0;
        icmp_packet->icmp_id = 0;
        icmp_packet->icmp_seq = seq++;
        memset(icmp_packet->icmp_data, 0, ICMP_PACKET_SIZE);
        icmp_packet->icmp_cksum = 0;
        icmp_packet->icmp_cksum = checksum((uint16_t *)icmp_packet, ICMP_PACKET_SIZE);
        printf("icmp_packet size:%lu\n", sizeof(struct icmp));
        int sent_bytes = sendto(sockfd, buf, sizeof(struct icmp), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
        if (sent_bytes <= 0) {
            perror("sendto error");
            break;
        }
 
        printf("sent icmp request:%d bytes to:%s\n", sent_bytes, argv[1]);
 
        int recv_bytes = recv(sockfd, buf, PACKET_SIZE, 0);
        if (recv_bytes <= 0) {
            perror("recv");
            break;
        }
        struct iphdr *ip_packet = (struct iphdr *)buf;
        struct icmp *icmp_reply = (struct icmp *)(buf + (ip_packet->ihl << 2));
        printf("recv icmp reply:%d from:%s\n", recv_bytes, inet_ntoa(dest_addr.sin_addr));
        printf("icmp type:%d,code:%d\n", icmp_reply->icmp_type, icmp_reply->icmp_code);
 
        sleep(1);
    }
 
    close(sockfd);
    return 0;
}

5.2、发送回显应答

#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <linux/in.h>
#include <arpa/inet.h>
 
#define IP_HDRLEN (20)
#define PACKET_SIZE (4096)
 
uint16_t checksum(uint16_t *buf, int len)
{
    unsigned long sum = 0;
    while (len > 1) {
        sum += *buf++;
        len -= 2;
    }
    if (len == 1) {
        sum += *(unsigned char *)buf;
    }
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    return ~sum;
}
 
uint16_t checksum_nofold(uint16_t *buf, int len)
{
    unsigned long sum = 0;
    while (len > 1) {
        sum += *buf++;
        len -= 2;
    }
    if (len == 1) {
        sum += *(unsigned char *)buf;
    }
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    return sum;
}
 
bool parse_pack(char *buf, uint32_t len) {
    struct icmp *icmp_packet = (struct icmp *)buf;
    uint16_t csum = checksum_nofold((uint16_t *)buf, len);
    printf("icmp csum:0x%04x\n", csum);
    return csum == 0xffff;
}
 
int main(int argc , char *argv[]) {
    int sockfd;
    int ret;
    char send_buf[PACKET_SIZE] = {0};
    char recv_buf[PACKET_SIZE] = {0};
 
    sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (sockfd == -1) {
        perror("socket error");
        return -1;
    }
 
    while(1) {
        struct sockaddr_in peer;
        socklen_t peerlen = sizeof(peer);
        memset(recv_buf, 0, PACKET_SIZE);
        ret = recvfrom(sockfd, recv_buf, PACKET_SIZE, 0, (struct sockaddr *)&peer, &peerlen);
        if (ret <= 0) {
            printf("ret:%d, errno:%d(%s)\n", ret, errno, strerror(errno));
        } else {
            printf("recv len:%d, peer src:port->%s:%d\n", ret, inet_ntoa(peer.sin_addr), ntohs(peer.sin_port));
            bool bret = parse_pack(recv_buf, ret);
            if (bret) {
                struct icmp *recv_icmp = (struct icmp *)(recv_buf + sizeof(struct iphdr));
                memset(send_buf, 0, PACKET_SIZE);
                struct icmp *icmp_packet = (struct icmp *)send_buf;
                icmp_packet->icmp_type = ICMP_ECHOREPLY;
                icmp_packet->icmp_code = 0;
                icmp_packet->icmp_id = 0;
                icmp_packet->icmp_seq = recv_icmp->icmp_seq;
                memset(icmp_packet->icmp_data, 0, sizeof(struct icmp));
                icmp_packet->icmp_cksum = 0;
                icmp_packet->icmp_cksum = checksum((uint16_t *)icmp_packet, sizeof(struct icmp));
                int sent_bytes = sendto(sockfd, send_buf, sizeof(struct icmp), 0, (struct sockaddr *)&peer, sizeof(peer));
                if (sent_bytes <= 0) {
                    perror("sendto error");
                    break;
                }
            }
        }
    }
 
    close(sockfd);
 
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/870827.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多传感器融合相关技术

重要说明&#xff1a;本文从网上资料整理而来&#xff0c;仅记录博主学习相关知识点的过程&#xff0c;侵删。 一、参考资料 多传感器融合定位学习 深蓝-多传感器定位融合 深蓝学院 多传感器融合定位 作业 多传感器融合详解 二、相关介绍 1. 毫米波雷达&#xff08;Radar&a…

mysql数据库设计

一、表关系 二、表结构 1、树状结构图&#xff08;id0表示根节点&#xff0c;parent_id是父节点&#xff09; 2、价格&#xff08;decimal类型&#xff09; 3、订单时间对应每一个订单状态&#xff08;前端展示、方便排查问题、数据分析&#xff09; 4、订单表存储商品信息&a…

LeetCode.26,27,88三题-双指针的运用

本文将对3道解决方法类似的题目进行逐一分析&#xff0c;这三道题目分别是&#xff1a; LeetCode.26 删除有序数组中的重复项 LeetCode.27 移除元素 LeetCode.88 合并两个有序数组 1. LeetCode.27 移除元素&#xff1a; 题目内容如下&#xff1a; 假设一个数组为&#xff1…

uniapp+vue3+vite+pinia2.0.33项目初始化

目录 准备工作 注意事项 使用vue-cli创建项目 运行 准备工作 下载hbuild开发工具 HBuilderX-高效极客技巧 下载微信小程序开发工具 概览 | 微信开放文档 uniapp uni-app官网 注意事项 1.node.js版本>16#windows查看node版本 C:\Users\22862>node -v v18.16.0 …

02Mysql之多表查询--例题讲解

一、题目详情&#xff0c;以及表的建立 新增员工表emp和部门表deptcreate table dept (dept1 int ,dept_name varchar(11));create table emp (sid int ,name varchar(11),age int,worktime_start date,incoming int,dept2 int);insert into dept values(101,财务),(102,销售)…

【数据中台商业化】数据中台微前端实践

一&#xff0c;需求背景 1 业务背景 在以往的业务场景中&#xff0c;用户进入五花八门的菜单体系中&#xff0c;往往会产生迷茫情绪&#xff0c;难以理解平台名称及具体作用&#xff0c;导致数据开发与管理学习成本较高&#xff0c;降低工作效率。为此我们整合从数据接入&…

不知道打仗之害,就不知道打仗之利

不知道打仗之害&#xff0c;就不知道打仗之利 【安志强趣讲《孙子兵法》第7讲】 【原文】 夫钝兵挫锐&#xff0c;屈力殚货&#xff0c;则诸侯乘其弊而起&#xff0c;虽有智者&#xff0c;不能善其后矣。 【注释】 屈力殚货&#xff1a;屈力&#xff0c;指力量消耗&#xff0c;…

掌握Python的X篇_32_使用python编辑pdf文件_pdfrw

本篇介绍利用python操作pdf文件&#xff0c;我们平时也会有合并和拆分pdf的需求&#xff0c;此时我们就可以使用本节内容。 文章目录 1. pdfrw的安装2. 切分pdf文件3. pdfrw官网及实现一版四面的实例 1. pdfrw的安装 pip install pdfrw官网地址&#xff1a;https://github.co…

设计模式之责任链模式【Java实现】

责任链&#xff08;Chain of Resposibility&#xff09; 模式 概念 责任链&#xff08;chain of Resposibility&#xff09; 模式&#xff1a;为了避免请求发送者与多个请求处理者耦合在一起&#xff0c;于是将所有请求的处理者 通过前一对象记住其下一个对象的引用而连成一条…

Mysql中插入数据,并返回自增主键的值

创建数据库和表使用 insert into 进行插入数据使用 RETURN_GENERATED_KEYS 进行返回插入的这条数据 具体方法如下&#xff1a; Testvoid addGetPk(){try{Statement stmt conn.createStatement();String sql String.format("insert into t_students values(null,%s,%s,%d…

Git:在本地电脑上如何使用git?

git 版本&#xff1a; 2.40.1.windows.1 文章目录 一. 使用git之前你必须要理解的几个概念1.1 理解工作区、版本库、暂存区的概念1.2 提交Git版本库的步骤【分两步执行】 二. Git本地库实战2.1 初始化版本库2.2 新建 & 提交 & 状态2.3 查看日志2.4 回退 & 穿梭 &am…

Linux驱动-基于Buildroot构建系统镜像后实现基于QT项目开发之环境配置

Linux驱动-基于Buildroot构建系统镜像后实现基于QT项目开发之环境配置 需求BuildRootUboot的仓库地址和commit idKernel 的仓库地址和commit id BuildRoot已编译库在Windows上的Create上创建项目编译QT项目 需求 基于Build root编译整个镜像后&#xff0c;如何开发自己的基于Q…

D* 算法完全解析(应该是全网最详细的吧)

花了几天时间学习了下 D* 算法&#xff0c;只能说熟悉了一下流程&#xff0c;远不能说掌握&#xff0c;算法实在是非常巧妙 参考 《制造车间无人搬运系统调度方法研究》 《基于D*Lite算法的移动机器人路径规划研究》 人工智能: 自动寻路算法实现(四、D、D*算法) D* 算法 D*路径…

Pycharm社区版连接WSL2中的Mysql8.*

当前时间2023.08.13&#xff0c;Windows11中默认的WSL版本已经是2了&#xff0c;在WSL2中默认的Ubuntu版本已经是22.04&#xff0c;而Ubuntu22.04中默认的Mysql版本已经是8.*。 Wsl 2 中安装mysql WSL2中安装Mysql的方法参考自微软官方文档【开始使用适用于 Linux 的 Windows …

网络请求中,token和cookie有什么区别

HTTP无状态&#xff0c;每次请求都要携带cookie&#xff0c;以帮助识别用户身份&#xff1b; 服务端也可以向客户端set-cookie&#xff0c;cookie大小限制为4kb&#xff1b; cookie默认有跨域限制&#xff0c;不跨域共享和传递&#xff0c;例如&#xff1a; 现代浏览器开始禁…

使用Python和pyodbc库将文件信息插入Access数据库

将文件信息插入 Access 数据库的博客文章示例&#xff1a; 简介&#xff1a; 在日常编程工作中&#xff0c;我们经常需要处理文件和文件夹。有时&#xff0c;我们需要遍历文件夹中的所有文件&#xff0c;并将文件的路径、类型、文件名以及修改日期和创建日期等信息保存到数据库…

基于MIV的神经网络变量筛选

1.案例背景 一般神经网络中所包含的网络输人数据是研究者根据专业知识和经验预先选择好的,然而在许多实际应用中,由于没有清晰的理论依据,神经网络所包含的自变量即网络输入特征难以预先确定,如果将一些不重要的自变量也引入神经网络,会降低模型的精度,因此选择有意义的自变量特…

Flask 上下文是什么 ?

哈喽大家好&#xff0c;我是咸鱼。今天我们来聊聊什么是 Flask 上下文 咸鱼在刚接触到这个概念的时候脑子里蹦出的第一个词是 CPU 上下文 今天咸鱼希望通过这篇文章&#xff0c;让大家能够对 Flask 上下文设计的初衷以及应用有一个基本的了解 Flask 上下文 我们在使用 Flask 开…

【算法基础19-模拟队列】

模拟队列 算法示意图 算法的伪代码 例题 实现一个队列&#xff0c;队列初始为空&#xff0c;支持四种操作&#xff1a; push x – 向队尾插入一个数 x&#xff1b;pop – 从队头弹出一个数&#xff1b;empty – 判断队列是否为空&#xff1b;query – 查询队头元素。 现在要…

不做Linux就没前途吗?

答案当然是——并不会 我晚上回来的时候跟一个今年的毕业生聊天&#xff0c;他入职了一家公司&#xff0c;但是从事的不是Linux相关的工作。 我这里想说的是&#xff0c;做Linux可以赚钱&#xff0c;Linux现在是全世界最牛逼的开源项目一点都不为过&#xff0c;但是Linux也不是…