《Linux实现ICMP PING代码》

《C语言实现ICMP协议,并进行PING测试》

《本文源代码下载》

目录

源代码

icmpping.c

icmpping.h

main.c

makefile

测试结果


源代码

icmpping.c

/***  实现 ICMP ping功能,检测 目的 IP地址通路,并计算时延*  *  作者: RToax*  日期: 2020年10月12日*/
#include <stdio.h>
#include <signal.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/timerfd.h>
#include <sys/time.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netdb.h>
#include <errno.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <pthread.h>#include "icmpping.h"#ifndef offsetof
#define offsetof(type, member)    ( (int) & ((type*)0) -> member )
#endif#define ICMP_BUF_SIZE           256
#define ICMP_RECVBUF_SIZE       (50 * 1024)
#define ICMP_MAGIC_ID           0xf1f2
#define ICMP_PROTO_NAME         "icmp"
#define ICMP_DATA               "Rong Tao's ICMP Ping"#define ICMP_PING_SUCC          __ICMP_PING_SUCC
#define ICMP_PING_FAIL          __ICMP_PING_FAIL#define ICMP_LOG(fmt...)        //printf(fmt)#define ICMP_LOG_ERR(fmt...)    fprintf(stderr, fmt);typedef enum {__ICMP_PING_FAIL = ICMPPING_FAIL,__ICMP_PING_SUCC = ICMPPING_SUCC,
}icmp_ping_rlst_t;/* type of icmp ping */
typedef struct __icmp_ping_s {int sockfd;struct sockaddr_in dst_addr, from_addr;int ntx, nrx, ntry;   //number of send pkg and recv pkgint tx, rx;int timeout_s;  //time out secondint (*log)(const char *fmt, ...);int rslt; //__ICMP_PING_XXXX
}icmp_ping_t;/* functions */
static icmp_ping_t* icmp_ping_init(const char *ipv4, int timeout_sec, int ntry, int (*log)(const char *fmt, ...));
int icmp_ping(const char *ipv4, unsigned int timeout, int ntry, int (*log)(const char *fmt, ...), long int *latency);
static void icmp_ping_finish (icmp_ping_t *ping);
static int icmp_ping_destroy(icmp_ping_t* ping);static int icmp_socket();
static int icmp_dst_addr(const char *addrHost, struct sockaddr_in * dst_addr);
static unsigned short icmp_gen_chksum(unsigned short * data, int len);
static int icmp_pkg_pack(void *buffer, int pack_no, const void *data, int data_size);
static int icmp_send_pkg(icmp_ping_t *ping, const void *data, int size);
static int icmp_recv_pkg(icmp_ping_t *ping, void *recvbuf, int size);
static int icmp_pkg_unpack(icmp_ping_t *ping, char * buf, int len);static void __icmp_timeval_sub(struct timeval * out, struct timeval * in);/* alogrithm of checksum */
static unsigned short icmp_gen_chksum(unsigned short * data, int len)
{int             nleft   = len;int             sum     = 0;unsigned short  *w      = data;unsigned short  answer  = 0;while (nleft > 1){sum += *w++;nleft -= 2;}if (nleft == 1){* (unsigned char *) (&answer) = *(unsigned char *)w;sum += answer;}sum     = (sum >> 16) + (sum & 0xffff);sum     += (sum >> 16);answer  = ~sum;return answer;
}/* create a socke to icmp */
static int icmp_socket()
{int sockfd;int size = ICMP_RECVBUF_SIZE;struct protoent * protocol  = NULL;if ((protocol = getprotobyname(ICMP_PROTO_NAME)) == NULL){ICMP_LOG_ERR("getprotobyname error.\n\r");return -1;}if ((sockfd = socket(AF_INET, SOCK_RAW, protocol->p_proto)) < 0){ICMP_LOG_ERR("socket error.\n\r");return -1;}if(setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size))!=0){ICMP_LOG_ERR("setsockopt SO_RCVBUF error.\n\r");close(sockfd);return -1;}
#if 1    struct timeval timeout = {1,0}; //secif(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(struct timeval))!=0){ICMP_LOG_ERR("setsockopt SO_RCVTIMEO error.\n\r");close(sockfd);return -1;}
#endif    return sockfd;
}/* get dst address */
static int icmp_dst_addr(const char *addrHost, struct sockaddr_in * dst_addr)
{struct hostent  * host      = NULL;unsigned long   inaddr      = 0;bzero(dst_addr, sizeof(struct sockaddr_in));dst_addr->sin_family = AF_INET;if ((inaddr = inet_addr(addrHost)) == INADDR_NONE){if ((host = gethostbyname(addrHost)) == NULL){ICMP_LOG_ERR("gethostbyname error.\n\r");return (-1);}memcpy((char *) &dst_addr->sin_addr, host->h_addr, host->h_length);}else {memcpy((char *) &dst_addr->sin_addr, (char *) &inaddr, sizeof(dst_addr->sin_addr));}return 0;
}/* set icmp hdr */
static int icmp_pkg_pack(void *buffer, int pack_no, const void *data, int data_size)
{int i, packsize = 0;struct icmp * icmp  = malloc(sizeof(struct icmp));icmp->icmp_type     = ICMP_ECHO;icmp->icmp_code     = 0;icmp->icmp_cksum    = 0;icmp->icmp_seq      = htons(pack_no);icmp->icmp_id       = htons(ICMP_MAGIC_ID);gettimeofday((struct timeval *) &icmp->icmp_data, NULL);memcpy(buffer, icmp, sizeof(struct icmp));packsize += sizeof(struct icmp);if(data && data_size){memcpy(buffer+packsize, data, data_size);packsize += data_size;}return packsize;
}/* send icmp package */
static int icmp_send_pkg(icmp_ping_t *ping, const void *data, int size)
{int             packetsize;unsigned short  checksum = 0;int             n = 0;char pkg_buffer[ICMP_BUF_SIZE];packetsize  = icmp_pkg_pack(pkg_buffer, ping->ntx, data, size);checksum    = icmp_gen_chksum((unsigned short *)pkg_buffer, packetsize);#define ICMP_PKG_CHKSUM_OFFSET  offsetof(struct icmp, icmp_cksum)
#define ICMP_PKG_CHKSUM_SIZE    2memcpy(pkg_buffer + ICMP_PKG_CHKSUM_OFFSET, &checksum, ICMP_PKG_CHKSUM_SIZE);if ((n = sendto(ping->sockfd, pkg_buffer, packetsize, 0, (struct sockaddr *) &ping->dst_addr, sizeof(struct sockaddr_in)))< 0){ICMP_LOG_ERR("sendto error. n = %d\n\r", n);return 0;}ping->ntx++;return n;
}/* send icmp package */
static int icmp_recv_pkg(icmp_ping_t *ping, void *recvbuf, int size)
{int n, fromlen;fromlen = sizeof(struct sockaddr_in);if ((n = recvfrom(ping->sockfd, recvbuf, size, 0, (struct sockaddr *) &ping->from_addr, &fromlen)) < 0){ICMP_LOG_ERR("recvfrom error.n = %d\n\r", n);return 0;}ping->nrx++;return n;
}/* unpack icmp pkg */
static int icmp_pkg_unpack(icmp_ping_t *ping, char * buf, int len)
{int     i, iphdrlen;struct  ip * ip = NULL;struct  icmp * icmp = NULL;struct  timeval * tvsend = NULL;double  rtt;ip          = (struct ip *)buf;iphdrlen    = ip->ip_hl << 2;icmp        = (struct icmp *) (buf + iphdrlen);len        -= iphdrlen;if (len < 8){ICMP_LOG_ERR("ICMP packet\'s length is less than 8\n\r");return - 1;}/* ensure icmp reply is mine response msg */if ((icmp->icmp_type == ICMP_ECHOREPLY) && (icmp->icmp_id = ntohs(ICMP_MAGIC_ID))){tvsend  = (struct timeval *)icmp->icmp_data;struct timeval tvrecv;gettimeofday(&tvrecv, NULL);__icmp_timeval_sub(&tvrecv, tvsend);rtt = tvrecv.tv_sec * 1000 + tvrecv.tv_usec / 1000;if(ping->log)ping->log("%d byte from %s: icmp_req=%u ttl=%d rtt=%.3f ms\n\r", len, inet_ntoa(ping->from_addr.sin_addr), ntohs(icmp->icmp_seq), ip->ip_ttl, rtt);}else {return - 1;}return 0;
}static void __icmp_timeval_sub(struct timeval * out, struct timeval * in)
{if ((out->tv_usec -= in->tv_usec) < 0){--out->tv_sec;out->tv_usec += 1000000;}out->tv_sec -= in->tv_sec;
}/**********************************************************************************************************************/
/* icmp ping with timeout */
static void icmp_ping_finish (icmp_ping_t *ping)
{if(ping->log){ping->log("\n--- ping statistics ---\n\r");ping->log("%d packets transmitted, %d received, %d%% lost\n\r", ping->ntx, ping->nrx, (ping->ntx - ping->nrx) / ping->ntx * 100);}if(ping->ntx == ping->ntry)ping->rslt = __ICMP_PING_SUCC;return;
}static icmp_ping_t* icmp_ping_init(const char *ipv4, int timeout_sec, int ntry, int (*log)(const char *fmt, ...))
{icmp_ping_t *ping = (icmp_ping_t *)malloc(sizeof(icmp_ping_t));if(!ping) return NULL;memset(ping, 0x00, sizeof(icmp_ping_t));ping->sockfd    = icmp_socket();ping->timeout_s = timeout_sec;ping->ntry      = ntry;ping->log       = log;icmp_dst_addr(ipv4, &ping->dst_addr);if(ping->log)ping->log("PING %s(%s): %d bytes data in ICMP packets.\n\r", ipv4, inet_ntoa(ping->dst_addr.sin_addr), sizeof(ICMP_DATA));return ping;
}static int icmp_ping_destroy(icmp_ping_t* ping)
{if(ping){close(ping->sockfd);free(ping);}ping = NULL;
}
static long int timeval_sub_usec(const struct timeval *before, const struct timeval *after)
{long int usec_diff = 0;usec_diff = (after->tv_sec-before->tv_sec)*1000000 + after->tv_usec-before->tv_usec;return usec_diff;
}/* PING */
int icmp_ping(const char *ipv4, unsigned int timeout, int ntry, int (*log)(const char *fmt, ...), long int *latency)
{icmp_ping_t *ping = icmp_ping_init(ipv4, timeout, ntry, log);struct timeval starttime, endtime;long int usec_diff = 0;char pkg_buffer[ICMP_BUF_SIZE];ping->rslt = __ICMP_PING_FAIL;while(ping->ntx < ping->ntry){gettimeofday(&starttime, NULL);ping->tx = icmp_send_pkg(ping, ICMP_DATA, sizeof(ICMP_DATA));if(ping->tx < 8) {ping->rslt = __ICMP_PING_FAIL;break;}ping->rx = icmp_recv_pkg(ping, pkg_buffer, ping->tx);if(ping->rx<8) {ping->rslt = __ICMP_PING_FAIL;break;}gettimeofday(&endtime, NULL);usec_diff += timeval_sub_usec(&starttime, &endtime);
//        printf("usec_diff = %ld\n", usec_diff);if (icmp_pkg_unpack(ping, pkg_buffer, ping->rx) == -1)continue;//sleep(1);}if(latency) *latency = (long int)(usec_diff / ping->ntry);icmp_ping_finish(ping);icmp_ping_destroy(ping);return ping->rslt;
}

icmpping.h

/***  实现 ICMP ping功能,检测 目的 IP地址通路,并计算时延*  *  作者: RToax*  日期: 2020年10月12日*/
#ifndef __ICMP_PING_H
#define __ICMP_PING_H 1/* icmp_ping 返回值 */
#define ICMPPING_SUCC   0   /* 成功 */
#define ICMPPING_FAIL   1   /* 失败 *//***  icmp_ping   - icmp ping*  *  param[in]   ipv4:       目的IPv4地址*  param[in]   timeout:    超时设置,若超出设定值,且ping不通情况下,函数自动返回*  param[in]   ntry:       ping的次数,发 req包数量*  param[in]   log:        打印调试信息,若为 NULL则不打印*  param[in]   latency:    计算平均时延,单位 微妙 micro second(参见结构 struct timeval)*                          该参数 填 NULL 时,不计算时延**  return  成功返回 ICMPPING_SUCC, 失败返回 ICMPPING_FAIL*/
int icmp_ping(const char *ipv4, unsigned int timeout, int ntry, int (*log)(const char *fmt, ...), long int *latency);#endif /*<__ICMP_PING_H>*/

main.c

#include <stdio.h>
#include "icmpping.h"int main(int argc, char * argv[])
{if (argc < 2){printf("Usage: %s hostname/IP address\n\r", argv[0]);return (-1);}long int latency;int rslt = icmp_ping(argv[1], 1, 3, NULL, &latency);if(rslt == ICMPPING_SUCC)printf("ping \033[1;32m%s\033[m is OK. latency = %ld microseconds\n", argv[1], latency);elseprintf("ping \033[1;31m%s\033[m is not OK.\n", argv[1]);return 0;
}

makefile

# 编译makefile
# RToax 2020年10月12日ICMP_INC := -I ./
ICMP_SRC := icmpping.cICMP_DEP := icmpping.oICMP_TARGET=icmppingall:$(ICMP_TARGET)$(ICMP_DEP): $(ICMP_SRC)gcc -c $(ICMP_SRC) $(ICMP_INC) -o $(ICMP_DEP)$(ICMP_TARGET): $(ICMP_DEP)gcc $(ICMP_DEP) main.c $(ICMP_INC) -o $(ICMP_TARGET)clean:rm -f $(ICMP_DEP) $(ICMP_TARGET)

测试结果

[root@localhost icmpping]# ./icmpping 0
ping 0 is OK. latency = 18 microseconds
[root@localhost icmpping]# ./icmpping 127.0.0.1
ping 127.0.0.1 is OK. latency = 15 microseconds
[root@localhost icmpping]# ./icmpping 10.170.6.24
ping 10.170.6.24 is OK. latency = 231 microseconds
[root@localhost icmpping]# ./icmpping 10.37.8.37
ping 10.37.8.37 is OK. latency = 20744 microseconds

Linux系统实现ICMP ping功能,并计算时延相关推荐

  1. linux中bash的功能主要有,Linux系统中的Bash功能的介绍

    今天小编要跟大家分享的文章是关于Linux系统中的Bash功能的介绍.一个完整计算机的体系结构包括:硬件与软件,而软件又分为系统软件与应用软件,负责对硬件仅需管理与操作的是系统软件的内核部分,用户是无 ...

  2. linux系统怎么ping命令,Linux系统下的ping命令的使用

    学习计算机网络的时候,常用的网络诊断工具比如ping.ipconfig命令这些都是我们经常要使用的,主要是用来监测网络是否通顺,相信你在Windows中已经是有经常使用过,并且也可以在dos系统下面可 ...

  3. Linux系统Bash的常用功能(9)

    了解了基本的Linux文件文件系统的概念后,我们将更深入的了解一下Linux的其他方面的内容,那就是我们所使用的用户接口,也就是大家常听到的 『Shell』 ,『这个shell并不是黑客反弹的shel ...

  4. 在Linux系统中使用蓝牙功能的基本方法

    首先确定硬件上有支持蓝牙的设备,然后运行如下命令,就可以开到我们的蓝牙设备了: lsusb 运行hciconfig可以看到: 从上图可以看出,我们的蓝牙设备是hci0 运行hcitool dev可以看 ...

  5. VB纯API实现强化Ping功能,替代系统自带Ping功能!

    本程序代码引用借鉴了两位前辈的代码: https://www.cnblogs.com/lichmama/p/3826565.html https://blog.csdn.net/jessezappy/ ...

  6. 类linux系统/proc/sysrq-trigger文件功能作用

    立即重启计算机      echo "b" > /proc/sysrq-trigger 立即关闭计算机      echo "o" > /proc/ ...

  7. Linux 系统中的dvfs功能

    前言 最近硬件的同事需要我们提供的版本能动态调频,何为动态调频呢?对于CPU来讲,功耗和性能是一对不可调和的矛盾,通过调整CPU的电压和频率,可以在功耗和性能之间找一个平衡点.由于调整是在系统运行的过 ...

  8. linux系统 设置网卡ping通主机连上外网

    上节https://blog.csdn.net/weixin_39816740/article/details/80255563 1.登陆系统 2.说明网卡没启动 3.按照我的做不会错 设置ip   ...

  9. linux系统更新失败处理功能,Proxmox VE升级apt-get update失败处理 | linux运维小站–linux系统架构_服务器运维_Linux运维工程师工作手札...

    安装每一个系统之后第一件事习惯性地升级系统,比如Centos.Redhat执行yum update,ubuntu.Debian执行apt-get update,但是昨天在安装完Proxmox VE执行 ...

最新文章

  1. iOS开发者知识普及,Swift 挑战 Objective-C,谁会笑到最后?...
  2. 拜托,别问我什么各种Tree了,干就完事!
  3. DATEIF实例说明3
  4. 使用overlap-add方法计算两个信号的卷积示例(在频域计算卷积)
  5. 找出数组中被其他元素整除的元素_「每日一题」数组中重复的数字
  6. 这位电子工程师,你不能错过。
  7. eeprom的wp 引脚_EEPROM存储芯片24C02
  8. leetcode53. 最大子数组和(暴力+贪心)
  9. Network下方什么请求也没有_今日头条上传图片时设置封面图报像素低的原因是什么...
  10. 第三十一章 考试作弊
  11. 【数据结构与算法】主宰这个世界的10大算法
  12. python抓取gb2312/gbk编码网页乱码问题
  13. matlab 曲线拐点_如何用matlab把一组数据模拟一个函数图像?并找出曲线拐点?...
  14. vb连接mysql未发现_vb连接mysql(错误代码)
  15. 在线URL编码加密工具
  16. Linux网卡up但是没有running,eth0 up但是没有running的小问题
  17. 20162330 第十周 蓝墨云班课 十字链表
  18. 在Elasticsearch中回测隨機(Stochastic)指標交叉交易策略
  19. 【译】浏览器如何工作:在现代web浏览器场景的之下
  20. 【思特奇杯·云上蓝桥-算法集训营】第1周——了解算法与数据结构

热门文章

  1. Linq:使用Take和Skip实现分页
  2. Codeforces-339D. Xenia and Bit Operations
  3. Cookie学习总结
  4. QQ5.0左侧滑动显示效果
  5. java RuntimeException
  6. 【译】组织好你的Asp.Net MVC解决方案
  7. bootstraptable不显示数据_单片机显示原理
  8. mfc远程连接mysql数据库连接_MFC连接mysql数据库(十分钟搞定)
  9. DPVS_吊打面试官的项目——DPVS
  10. 友元函数可以访问私有成员吗_C++的友元函数和友元类