ping

ping是怎么实现的?它依赖的是原始套接字与ICMP(Internet Control Message Protocol,网际控制消息协议),向目标主机投递回射请求,而目标主机将响应一个回射应答。通常在请求体中包含时间戳,用来计算RTT(Round-trip Time,回环时间),也就是玩家常说的服务器延迟了。

int
main(int argc, char **argv)
{
    int c;
    struct addrinfo *ai;
    char *h;

opterr = 0;
    while((c = getopt(argc, argv, "v")) != -1)
    {
        switch(c)
        {
        case ‘v‘:
            verbose++;
            break;

case ‘?‘:
            printf("unrecognized option: %c\n", c);
            return -1;
        }
    }

if(optind != argc-1)
    {
        printf("usage: ping [-v] <hostname>\n");
        return -1;
    }
    host = argv[optind];

pid = getpid() & 0xffff;
    signal(SIGALRM, sig_alrm);

ai = host_serv(host, NULL, 0, 0);

h = sock_ntop_host(ai->ai_addr, ai->ai_addrlen);
    printf("PING %s (%s): %d data bytes\n",
        ai->ai_canonname ? ai->ai_canonname : h, h, datalen);

if(ai->ai_family == AF_INET)
    {
        pr = &proto_v4;
    }
    else
    {
        printf("cannot ping IPv4-mapped IPv6 address\n");
        return -1;
    }
    pr->sasend = ai->ai_addr;
    pr->sarecv = (sockaddr*)calloc(1, ai->ai_addrlen);
    pr->salen = ai->ai_addrlen;

readloop();
}

void
readloop()
{
    int size;
    char recvbuf[BUFSIZE];
    char controlbuf[BUFSIZE];
    struct msghdr msg;
    struct iovec iov;
    ssize_t n;
    struct timeval tval;

sockfd = socket(pr->sasend->sa_family, SOCK_RAW, pr->icmpproto);
    setuid(getuid());
    if(pr->finit)
        (*pr->finit)();

size = 60 * 1024;
    setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));

sig_alrm(SIGALRM); // 发送部分,下面先分析此部分

iov.iov_base = recvbuf;
    iov.iov_len = sizeof(recvbuf);
    msg.msg_name = pr->sarecv;
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;
    msg.msg_control = controlbuf;
    for(;;)
    {
        msg.msg_namelen = pr->salen;
        msg.msg_controllen = sizeof(controlbuf);
        n = recvmsg(sockfd, &msg, 0);
        if(n < 0)
        {
            if(errno == EINTR)
                continue;
            else
            {
                printf("recvmsg error\n");
                exit(-1);
            }
        }
        gettimeofday(&tval, NULL);
        (*pr->fproc)(recvbuf, n, &msg, &tval); // 接受部分
    }
}

void
sig_alrm(int signo)
{
    (*pr->fsend)(); // 构造一个ICMP回射请求
    alarm(1); // 定时发包
}

void
send_v4()
{
    int len;
    struct icmp *icmp;

icmp = (struct icmp*)sendbuf;
    icmp->icmp_type = ICMP_ECHO;
    icmp->icmp_code = 0;
    icmp->icmp_id = pid;
    icmp->icmp_seq = nsent++;
    memset(icmp->icmp_data, 0xa5, datalen);
    gettimeofday((struct timeval*)icmp->icmp_data, NULL);
    
    len = 8 + datalen;
    icmp->icmp_cksum = 0;
    icmp->icmp_cksum = in_cksum((u_short*)icmp, len);

sendto(sockfd, sendbuf, len, 0, pr->sasend, pr->salen); // 虽然是原始套接字,但IP头由OS添加
}

void
proc_v4(char *ptr, ssize_t len, struct msghdr *msg, struct timeval *tvrecv)
{
    int hlenl, icmplen;
    double rtt;
    struct ip *ip;
    struct icmp *icmp;
    struct timeval *tvsend;

ip = (struct ip*)ptr; // 但接受到的则是整个IP包了,要自己提取ICMP部分
    hlenl = ip->ip_hl << 2;
    if(ip->ip_p != IPPROTO_ICMP)
        return;
    
    icmp = (struct icmp*)(ptr + hlenl);
    if((icmplen = len - hlenl) < 8)
        return;

if(icmp->icmp_type == ICMP_ECHOREPLY)
    {
        if(icmp->icmp_id != pid)
            return;
        if(icmplen < 16)
            return;
        tvsend = (struct timeval*)icmp->icmp_data;
        tv_sub(tvrecv, tvsend);
        rtt = tvrecv->tv_sec * 1000.0 + tvrecv->tv_usec / 1000.0;

printf("%d bytes from %s: seq=%u, ttl=%d, rtt=%.3f ms\n",
            icmplen, sock_ntop_host(pr->sarecv, pr->salen), icmp->icmp_seq, ip->ip_ttl, rtt);

}
    else if(verbose)
    {
        printf("%d bytes from %s: type=%d, code=%d\n",
            icmplen, sock_ntop_host(pr->sarecv, pr->salen), icmp->icmp_type, icmp->icmp_code);
    }
}

时间: 2024-08-10 02:08:37

ping的相关文章

C# Ping 简单使用

编程过程中,有时候需要判断主机是否在线,最简单的方法就是使用Windows的Ping命令看看能否ping通.看到网上很多文章,说用C#去调用windows的ping.exe,然后解析返回的字符串.我觉得这种方式太麻烦了,就做一下简单判断,不想弄那么麻烦. 查了一下,C#专门提供了一个Ping类,与Windows下的ping命令类似: 命令空间: System.Net.NetworkInformation; 使用方法: bool online = false; //是否在线 Ping ping =

docker run常用命令及 解决 ubuntu镜像无法识别 ifconfig ping 命令

docker run -it     docker 前端启动 container容器           -d             后端启动 container容器           -p             固定端口映射            -P             不固定端口映射           --name         给生成的容器起名字docker ps:默认显示正在运行的container       ps -a 显示所有的container容器docker r

red hat7 系统可以ping通ip地址但是不能ping通域名

在red hat7中ifconfig后出现这样的情况,ens33是物理网卡,与eth0一样只是不同的名字.但是只能ping通ip地址不能ping通域名. 解决方法: 在文件 /etc/resolv.conf文件下更改nameserver的值 加上 nameserver 8.8.8.8  域名解析服务  nameserver 8.8.4.4为备用的 在文件 etc/sysconfig/network-scripts下修改 ifcfg-eth0 或者 ifcfg-ens33文件,设置静态ip地址,

redis error It was not possible to connect to the redis server(s); to create a disconnected multiplexer, disable AbortOnConnectFail. SocketFailure on PING

应用redis出现如下错误 It was not possible to connect to the redis server(s); to create a disconnected multiplexer, disable AbortOnConnectFail. SocketFailure on PING 参考stack overflow上文章 http://stackoverflow.com/questions/30895507/it-was-not-possible-to-connec

小白日记8:kali渗透测试之主动信息收集(二)三层发现:ping、traceroute、scapy、nmap、fping、Hping

三层发现 三层协议有:IP以及ICMP协议(internet管理协议).icmp的作用是用来实现intenet管理的,进行路径的发现,网路通信情况,或者目标主机的状态:在三层发现中主要使用icmp协议,arp协议属于二层协议,它是基于广播的,所以不可路由.而ICMP协议是可以路由的,理论上可以使用icmp协议发现全球的ip,如果没有边界防火墙(禁止icmp的探测包)进行过滤的话,对目标主机进行扫描,则会收到相应的响应,从而进行捕捉[有边界防火墙的现象比较普遍],但是三层发现的扫描速度也较二层要慢

icmp实现ping

以前弄到的一段代码, 一个用原始套接字raw socket实现icmp协议ping工具 myping.c #include <stdio.h> #include <errno.h> #include <signal.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <stri

ping查看设备网络是否可达

#!/bin/bash # 在centos系统上面执行 # 执行方法: sh centospingbjbk.sh iplist1.txt # 输入: iplist.txt(ip列表).警告,只能是ip,不能是host # 输出: faillist.txt(ping不通的ip列表).oklist.txt(ping通的ip列表) # yuanlong.zhou # 2015.09.25 iplist=$1 cat /dev/null > faillist.txt && cat /dev/

笔记本无线连接时(无本地连接) 与本地虚拟机相互ping通

桥接模式: 1.虚拟机选择 桥接模式 2. 虚拟网络桥接到的网络选择无线网卡(选择正在使用的网卡即可) 3.查看笔记本电脑无线网卡的IP地址  192.168.200.103 4.将虚拟机的IP设置为与笔记本无线网ip同一网段  192.168.200.x 如:192.168.200.104 5.设置成功 测试 PC <--> 虚拟机  相互能ping同

Linux下用C实现Ping监测与HTTP报文上传

有一个数据中心监测项目,命名为CPing,它的主要原理通过WEB进行前台统一配置管理,后台定期对数据中心相关设备执行Ping操作,并将结果及时写入到数据库. 该项目基于Linux平台部署,前端开发语言采用PHP,后台开发语言采用C,由于考量到项目的部署简洁性,后台开发的守护进程尽量不直接操作数据库,而是将需要写入的数据以HTTP的形式发送给PHP的WEB页面,由PHP完成写入操作.这样的好处是后台守护进程部署时不需要配置相关数据库接入环境. 下面给出一段后台代码,作用是执行Ping操作,并将结果

线上一个简单检测Ping状态的邮件报警脚本

Step1.安装sendmail来发邮件 # yum -y install sendmail # /etc/init.d/sendmail start # chkconfig sendmail on Step2.安装邮件客户端 # yum -y install mutt 2.1添加发件人信息,如下 # vim /etc/Muttrc set charset="utf-8"           #设置发邮件编码 set envelope_from=yes set rfc2047_para