C语言实现ICMP

icmp.h

//
// Created by Victor on 2020/2/20.
//

#ifndef VPING_ICMP_H
#define VPING_ICMP_H

#include <stdint.h>
#include <stdbool.h>

/**
ICMPv4 Header
*/
typedef struct ICMPHeader{
    uint8_t type;
    uint8_t code;
    uint16_t checksum;
}ICMPHeader;

/**
Destination Unreachable Message "目的不可达消息格式"
type:消息类型,此处值为3。
Code:0 = net unreachable;网络不可达
     1 = host unreachable;主机不可达
     2 = protocol unreachable;协议不可达
     3 = port unreachable; 端口不可达,Tracert时发送的ICMP报文即为此类。
     4 = fragmentation needed and DF set;需要进行分片但设置不分片比特
     5 = source route failed.源站选路失败
     6 = Destination network unknown目的网络不认识
     7 = Destination host unknown目的主机不认识
     8 = Source host isolated (obsolete)源主机被隔离(作废不用)
     9 = Destination network administratively prohibited目的网络被强制禁止
     10 = Destination host administratively prohibited目的主机被强制禁止
     11 = Network unreachable for TOS由于TOS,网络不可达
     12 = Host unreachable for TOS 由于TOS,主机不可达
     13 = Communication administratively prohibited by filtering由于过滤,通信被强制禁止
     14 = Host precedence violation主机越权
     15 = Precedence cutoff in effect优先权中止生效
checkSum:检验和,使用和IP相同的加法校验和算法,但是ICMP校验和仅覆盖ICMP报文。
unused:4字节,未使用,必须填0。
data: Internet Header + 64 bits of Original Data Datagram
    IP首部+原始数据包的前8字节:
        1.IP首部:如果IP首部没有选项字段时为20字节
        2.原始数据包的前8字节:UDP首部的8字节或者TCP首部的8字节。
          该数据是主机用来匹配消息。对于更高层协议的用户端口号,原始数据包的前64比特的这些数据会被重组。
*/
#define ICMP_Type_Destination_Unreachable 3
//
#define ICMP_Code_Net_Unreachable 0
#define ICMP_Code_Host_Unreachable 1
#define ICMP_Code_Protocol_Unreachable 2
#define ICMP_Code_Port_Unreachable 3
#define ICMP_Code_Fragmentation_Needed_And_DF_Set 4
#define ICMP_Code_Source_Route_Failed 5

#define ICMP_Code_Destination_Network_Unknown 6
#define ICMP_Code_Destination_Host_Unknown 7
#define ICMP_Code_Source_Host_Isolated 8
#define ICMP_Code_Destination_Network_Administratively_Prohibited 9
#define ICMP_Code_Destination_Host_Administratively_Prohibited 10
#define ICMP_Code_Network_Unreachable_For_TOS 11
#define ICMP_Code_Host_Unreachable_For_TOS 12
#define ICMP_Code_Communication_AdministrativelyProhibited_By_Filtering 13
#define ICMP_Code_Host_Precedence_Violation 14
#define ICMP_Code_Precedence_Cutoff_In_Effect 15
typedef struct ICMPDestinationUnreachable{
    struct ICMPHeader iCMPHeader;
    uint32_t unused;
    uint8_t  data[];
}ICMPDestinationUnreachable;

/**
Time Exceeded Message "超时消息格式"
type:消息类型,此处值为3。
code:0 = time to live exceeded in transit
     1 = fragment reassembly time exceeded
checkSum:检验和,使用和IP相同的加法校验和算法,但是ICMP校验和仅覆盖ICMP报文。
unused:4字节,未使用,必须填0。
data: Internet Header + 64 bits of Original Data Datagram
    IP首部+原始数据包的前8字节:
        1.IP首部:如果IP首部没有选项字段时为20字节
        2.原始数据包的前8字节:UDP首部的8字节或者TCP首部的8字节。
          该数据是主机用来匹配消息。对于更高层协议的用户端口号,原始数据包的前64比特的这些数据会被重组。
*/
#define ICMP_Type_Time_Exceeded 3
//
#define ICMP_Code_Time_To_Live_Exceeded_InTransit 0
#define ICMP_Code_Fragment_Reassembly_Time_Exceeded 1
typedef struct ICMPTimeExceeded{
    struct ICMPHeader iCMPHeader;
    uint32_t unused;
    uint8_t data[];
}ICMPTimeExceeded;

/**
Parameter Problem Message
type: 12
code: 0 = pointer indicates the error.
*/
#define ICMP_Type_Parameter_Problem 12
//
#define ICMP_Code_Pointer_Indicates_The_Error 0
typedef struct ICMPParameterProblem{
    struct ICMPHeader iCMPHeader;
    uint8_t pointer;
    uint32_t unused:24;
    uint8_t data[];
}ICMPParameterProblem;

/**
Source Quench Message
type:4
code:0
*/
#define ICMP_Type_Quench_Message 4
//
#define ICMP_Code_Quench_Message 0
typedef struct ICMPSourceQuench{
    struct ICMPHeader iCMPHeader;
    uint32_t  unused;
    uint8_t data[];
}ICMPSourceQuench;

/**
Redirect Message "重定向消息"
type:消息类型,此处值为5。
Code:0 = Redirect datagrams for the Network
     1 = Redirect datagrams for the Host.
     2 = Redirect datagrams for the Type of Service and Network.
     3 = Redirect datagrams for the Type of Service and Host.
checkSum:校验和,使用和IP相同的加法校验和算法,但是ICMP校验和仅覆盖ICMP报文。
Gateway Internet Address:即原始数据包里的IP目的地址域。
data:Internet Header + 64 bits of Original Data Datagram
      IP头和原始数据包的前64比特数据。该数据是主机用来匹配消息。
      对于更高层协议的用户端口号,原始数据包的前64比特的这些数据会被重组。
*/
#define ICMP_Type_Redirect 5
//
#define ICMP_Code_Redirect_Datagrams_For_The_Network 0
#define ICMP_Code_Redirect_Datagrams_For_The_Host 1
#define ICMP_Code_Redirect_Datagrams_For_The_Type_Of_Service_And_Network 2
#define ICMP_Code_Redirect_Datagrams_For_The_Type_Of_Service_And_Host 3
typedef struct ICMPRedirect{
    struct ICMPHeader iCMPHeader;
    uint32_t gatewayInternetAddress;
    uint8_t data[];
}ICMPRedirect;

/**
Echo or Echo Reply Message   "Echo Request/Reply消息格式"
type:1字节 0:回显应答报文
           8:请求回显报文
Code:1字节 消息代码,此处值为0。
checkSum:2字节,校验和,使用和IP相同的加法校验和算法,但是ICMP校验和仅覆盖ICMP报文。
identifier:2字节,标识符,发送端标示此发送的报文。标识符可以像TCP或UDP中的端口一样使用
SequenceNumber:2字节,序列号,发送端发送的报文的顺序号。每发送一次顺序号就加1。
data:可变,字段的长度和内容,取决于消息的类型和代码,请参见表1。
*/
#define ICMP_Type_Echo_Request 8
#define ICMP_Type_Echo_Reply 0
//
#define ICMP_Code_Echo 0
typedef struct ICMPEcho{
    struct ICMPHeader iCMPHeader;
    uint16_t identifier;
    uint16_t sequenceNumber;
    uint8_t data[];
}ICMPEcho;

/**
uint16_t calculateICMPCheckSum(uint16_t *icmp,int size)
*/
uint16_t calculateICMPCheckSum(uint16_t *icmp);

/**
uint16_t validateICMPCheckSum(uint16_t *icmp,int size)
*/
bool validateICMPCheckSum(uint16_t *icmp);

/**
calculateICMPSize()
*/
int calculateICMPSize(void *icmp);
#endif //VPING_ICMP_H

icmp.c

//
// Created by Victor on 2020/2/20.
//

#include "icmp.h"
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>

/**
uint16_t iCMPCheckSum
*/
uint16_t calculateICMPCheckSum(uint16_t *icmp){
    int size = calculateICMPSize((void*)icmp);
    uint32_t checkSum = 0;
    int decrementValue = sizeof(uint16_t);
    //16位为单位数字相加
    while(size > 1){
        checkSum += *icmp++;     // 对传入的数据以uint16_t方式解析
        size -= decrementValue;
    }
    //长度奇数情况 size == 1
    if(size){
        checkSum += *(uint8_t*)icmp;
    }
    //高位有进位,进位到低位,下面两行代码保证了高16位为0。
    while (checkSum >> 16){
        checkSum = (checkSum >> 16) + (checkSum & 0xffff);
    }
    //最后按位取反
    return (uint16_t*)(~checkSum); // ~是按位取反
}

/**
uint16_t validateICMPCheckSum
 void *icmp 指针类型转换后++不是以转换后字节数累加的还是加1;(有待分析,奇怪)
*/
bool validateICMPCheckSum(uint16_t *icmp){
    int size = calculateICMPSize((void*)icmp);
    uint32_t checkSum = 0;
    int decrementValue = sizeof(uint16_t);
    //16位为单位数字相加
    while(size > 1){
        checkSum += *icmp++;     // 对传入的数据以uint16_t方式解析
        size -= decrementValue;
    }
    //长度奇数情况 size == 1
    if(size){
        checkSum += *(uint8_t*)icmp;
    }
    //高位有进位,进位到低位,下面两行代码保证了高16位为0。
    while (checkSum >> 16){
        checkSum = (checkSum >> 16) + (checkSum & 0xffff);
    }
    return (checkSum == 0xffff);
}

/**
calculateICMPSize
*/
int calculateICMPSize(void *icmp) {
    int offset = sizeof(uint64_t);
    uint8_t  *data = ((uint8_t*)icmp) + offset;
    return offset+(int)strlen((const char*)data)+1;
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,874评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,102评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,676评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,911评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,937评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,935评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,860评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,660评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,113评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,363评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,506评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,238评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,861评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,486评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,674评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,513评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,426评论 2 352