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 <string.h>
#include <fcntl.h>
#include <sys/time.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/ip_icmp.h>

#define ICMP_PACKET_SIZE 16
#define TIME_OUT_SECONDS 2

unsigned short cal_chksum(unsigned short *buf, int len)
{
    unsigned int sum = 0;
    unsigned short ret;

    while(len > 1) {
        sum += *buf;
        buf++;
        len -= 2;
    }
    if(1 == len) {
        sum += (*(unsigned char *)buf);
    }

    sum = (sum >> 16) + (sum & 0xFFFF);
    sum = (sum >> 16) + (sum & 0xFFFF);        //sum = (sum >> 16) + sum;

    ret = ~sum;

    return    ret;
}

int    pack_icmp(char *buf, int seq)
{
    struct    icmp *icmp_packet = (struct icmp *)buf;

    icmp_packet->icmp_type = ICMP_ECHO;
    icmp_packet->icmp_code = 0;
    icmp_packet->icmp_id = getpid();
    icmp_packet->icmp_seq = seq;
    icmp_packet->icmp_cksum = 0;    //must clean it before cal_chksum or you will get bad chksum(can‘t error when ping your own ipaddress )

    struct timeval tv;
    gettimeofday(&tv, NULL);

    memcpy(buf + 8, &tv, sizeof(tv));

    icmp_packet->icmp_cksum = cal_chksum((unsigned short *)icmp_packet,ICMP_PACKET_SIZE);

}

int parse_ip_icmp_info(void *buf, struct sockaddr_in answer)
{
    unsigned short chk_sum;
    unsigned char ttl;
    unsigned short seq;
    struct timeval tv_send, tv_now;
    unsigned int mini_sec;

    struct ip *ip_packet = (struct ip *)buf;
    struct icmp *icmp_packet = (struct icmp *)(buf + (ip_packet->ip_hl << 2));

    if(icmp_packet->icmp_id != getpid()) {
        return -1;
    }
    if(icmp_packet->icmp_type != ICMP_ECHOREPLY) {
        return -1;
    }

    ttl = ip_packet->ip_ttl;
    seq = icmp_packet->icmp_seq;
    chk_sum = icmp_packet->icmp_cksum;
    icmp_packet->icmp_cksum = 0;

    if(chk_sum != cal_chksum((unsigned short *)icmp_packet,ICMP_PACKET_SIZE)) {
        return -1;
    }

    gettimeofday(&tv_now, NULL);
    memcpy(&tv_send, ((char *)icmp_packet + 8), sizeof(tv_send));

    mini_sec = (tv_now.tv_sec - tv_send.tv_sec) * 1000000 +
                (tv_now.tv_usec - tv_send.tv_usec);

    printf("%d bytes data from: %s icmp_seq = %d, ttl = %d, times = %.3fms\n",
                (ip_packet->ip_hl << 2) + 16,
                inet_ntoa(answer.sin_addr),
                seq,
                ttl,
                mini_sec/1000.0);
    return    0;
}

int main(int argc, char *argv[])
{
    if(argc != 2) {
        printf("Usage: %s ipaddr/hostname\n", argv[0]);
        exit( 0 );
    }

    struct hostent * host = gethostbyname(argv[1]);
    if(host == NULL) {
        printf("ping: unknow host %s \n", argv[1]);
        exit(2);
    }

    struct sockaddr_in dest;
    dest.sin_family = AF_INET;
    memcpy( &dest.sin_addr, host->h_addr, sizeof(int));

    int sock_raw_fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if(sock_raw_fd == -1) {
        perror("socket");
        exit(1);
    }    

    char buf[ICMP_PACKET_SIZE];

    int seq = 0;

    char recv_buf[50];
    struct sockaddr_in answer;
    int answer_len = sizeof(answer);
    while(1) {
        seq ++;
        pack_icmp(buf, seq);
        sendto(sock_raw_fd, buf, ICMP_PACKET_SIZE, 0, (struct sockaddr *)&dest, sizeof(dest));

        while(1) {
            fd_set readset;
            FD_ZERO(&readset);
            FD_SET(sock_raw_fd, &readset);

            struct timeval tv;
            tv.tv_sec = TIME_OUT_SECONDS;
            tv.tv_usec = 0;

            int ret = select(sock_raw_fd+1, &readset, NULL, NULL, &tv);
            if(ret == -1) {
                perror("select");
                exit(3);
            } else if(ret == 0) {
                printf("time out.\n");
                break;
            } else {
                int resolve = 0;
                int ret = recvfrom(sock_raw_fd, recv_buf, 36, 0, (struct sockaddr *)&answer, &answer_len);

                if(ret > 0)
                    resolve = parse_ip_icmp_info(recv_buf, answer);
                if(resolve == 0)
                    break;
            }
        }
        sleep(1);
    }

    return 0;
}

编译链接执行. 输出如下:

时间: 2024-11-23 21:12:15

icmp实现ping的相关文章

Linux服务器关闭/开启ICMP协议(ping)

经常会遇到一些问题就是主机明明是在线的却ping不通的,对方可能开启了禁ping模式有时为安全问题着想,需要给我们的Linux服务器禁ping 关闭ICMP协议(禁ping) echo "1">/proc/sys/net/ipv4/icmp_echo_ignore_all cat /proc/sys/net/ipv4/icmp_echo_ignore_all 打开ICMP协议(取消禁ping) echo "0">/proc/sys/net/ipv4/ic

网络协议 5 - ICMP 与 ping:投石问路的侦察兵

????日常开发中,我们经常会碰到查询网络是否畅通以及域名对应 IP 地址等小需求,这时候用的最多的应该就是 ping 命令了. 那你知道 ping 命令是怎么工作的吗?今天,我们就来一起认识下 ping 命令及其对应的 ICMP 协议. ICMP 协议 ????ICMP 全称 Internet Control Message Protocol,指互联网控制报文协议. ????网络本身是不可靠的,数据包在传输过程中,可能会发生很多突发事件并导致数据传输失败.而网络层的 IP 协议是一个无连接的协

7(计算机网络) ICMP与ping

无论是在宿舍,还是在办公室,或者运维一个数据中心,我们常常会遇到网络不通的问题.那台机器明明就在那里,你甚至都可以通过机器的终端连上去看.它看着好好的,可是就是连不上去,究竟是哪里出了问题呢? ICMP 协议的格式 一般情况下,你会想到 ping 一下.那你知道 ping 是如何工作的吗? ping 是基于 ICMP 协议工作的.ICMP全称Internet Control Message Protocol,就是互联网控制报文协议.这里面的关键词是"控制",那具体是怎么控制的呢? 网络

4.ICMP协议,ping和Traceroute

1.IMCP协议介绍 前面讲到了,IP协议并不是一个可靠的协议,它不保证数据被送达,那么,自然的,保证数据送达的工作应该由其他的模块来完成.其中一个重要的模块就是ICMP(网络控制报文)协议. 当传送IP数据包发生错误--比如主机不可达,路由不可达等等,ICMP协议将会把错误信息封包,然后传送回给主机.给主机一个处理错误的机会,这 也就是为什么说建立在IP层以上的协议是可能做到安全的原因.ICMP数据包由8bit的错误类型和8bit的代码和16bit的校验和组成.而前 16bit就组成了ICMP

TCP/IP详解学习笔记(4)-ICMP协议,ping和Traceroute

转自:http://blog.csdn.net/goodboy1881/article/details/670761 ———————————————————————————————————————————————————————— 1.IMCP协议介绍 前面讲到了,IP协议并不是一个可靠的协议,它不保证数据被送达,那么,自然的,保证数据送达的工作应该由其他的模块来完成.其中一个重要的模块就是ICMP(网络控制报文)协议. 当传送IP数据包发生错误--比如主机不可达,路由不可达等等,ICMP协议将

ping的原理以及ICMP

ping 的原理: ping 程序是用来探测主机到主机之间是否可通信,如果不能ping到某台主机,表明不能和这台主机建立连接.     ping 使用的是ICMP协议,它发送icmp回送请求消息给目的主机.ICMP协议规定:目的主机必须返回ICMP回送应答消息给源主机.如果源主机在一定时间内收到应答,则认为主机可达. ICMP协议通过IP协议发送的,IP协议是一种无连接的,不可靠的数据包协议. ping.exe的原理: 向指定的IP地址发送一定长度的数据包,按照约定,若指定IP地址存在的话,会返

PING的原理以及ICMP协议

主要内容: 1.ping的原理以及工作过程 2.ICMP协议 3.ICMP的应用:ping,traceroute 1.ping的原理以及工作过程  ping的原理  ping 程序是用来探测主机到主机之间是否可通信,如果不能ping到某台主机,表明不能和这台主机建立连接. ping 使用的是ICMP协议,它发送icmp回送请求消息给目的主机.ICMP协议规定:目的主机必须返回ICMP回送应答消息给源主机.如果源主机在一定时间内收到应答,则认为主机可达. ICMP协议通过IP协议发送的,IP协议是

traceroute ping 开放(icmp|udp)

tarceroute ping 开放(icmp|udp) tarceroute原理ICMP应用之ping ping是一个用来查询网络通不通的一个工具,是系统自带的,运行于内核,调用ICMP协议. ping的工作原理:ping通过调用echo来发送请求,通过是否收到echo-reply来查询网络层的连通性.ping的结果会给出传送的时间和TTL的数据,还可以查看主机到目的主机的路由.这是因为ICMP的ping请求数据报在每经过一个路由器的时候,路由器就会把自己的IP地址放到该数据包中,而目的主机则

ICMP的应用--ping

ping这个单词源自声纳定位,而这个程序的作用也确实如此,它利用ICMP协议包来侦测另一个主机是否可达.原理是用类型码为0的ICMP发请 求,受到请求的主机则用类型码为8的ICMP回应.ping程序来计算间隔时间,并计算有多少个包被送达.用户就可以判断网络大致的情况.我们可以看到, ping给出来了传送的时间和TTL的数据.我给的例子不太好,因为走的路由少,有兴趣地可以ping一下国外的网站比如sf.net,就可以观察到一些 丢包的现象,而程序运行的时间也会更加的长. ping还给我们一个看主机