• icmp的程序(ping的实现)


    code来源于《网络编程与分层协议设计》 chap7 ICMP协议程序设计

    ----没有理解,没有编译,只是敲了出来

    ping.h

    #define ICMP_ECHOREPLY 0
    #define ICMP_ECHO 8

    #define BUFSIZE 1500
    #define DEFAULT_LEN 56


    typedef unsigned char u8;
    typedef unsigned short u16;
    typedef unsigned int u32;


    struct icmphdr{
    u8 type;
    u8 code;
    u16 checksum;
    union{
    struct {
    u16 id;
    u16 sequence;
    }echo;
    u32 gateway;
    struct
    {
    u16 unused;
    u16 mtu;
    }frag;
    }un;
    u8 data[0];
    #define icmp_id un.echo.id
    #define icmp_seq un.echo.sequence
    };
    #define ICMP_HSIZE sizeof(struct icmphdr)

    struct iphdr{
    u8 hlen:4, ver:4;
    u8 tos;
    u16 tot_len;
    u16 id;
    u16 frag_off;
    u8 ttl;
    u8 protocol;
    u16 check;
    u32 saddr;
    u32 daddr;
    };

    char *hostname;
    int datalen = DEFAULT_LEN;
    char sendbuf[BUFSIZE];
    char recvbuf[BUFSIZE];
    int nsent;
    int nrecv;
    pid_t pid;
    struct timeval recvtime;
    int sockfd;
    struct sockaddr_in dest;
    struct sockaddr_in from;
    struct sigaction act_alarm;
    struct sigaction act_int;


    void alarm_handler(int);
    void int_handler(int);
    void set_sighandler();
    void send_ping();
    void recv_reply();
    u16 checksum(u8 *buf, int len);
    int handle_pkt();
    void get_statistics(int, int);
    void bail(const char *)

    ping.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/time.h>
    #include <unistd.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netdb.h>
    #include <errno.h>
    #include <arpa/inet.h>
    #include <signal.h>
    #include <netinet/in.h>

    #include "ping.h"

    struct itimerval val_alarm={.it_interval.tv_sec = 1,
    .it_interval.tv_usec = 0,
    .it_value.tv_sec = 0,
    .it_value.tv_usec = 1
    };

    int main(int argc, char **argv)
    {
    struct hostent *host;

    if (argc < 2){
    printf("Usuage: %s hostname ", argv[0]);
    exit(1);
    }

    if (host = gethostbyname(argv[1]) == NULL){
    perror("can not understand the host name");
    exit(1);
    }

    hostname = argv[1];

    memset(&dest, 0, sizeof(dest));
    dest.sin_family = PF_INET;
    dest.sin_port = ntohs(0);
    dest.sin_addr = *(struct in_addr *)host->h_addr_list[0];

    if ((sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0){
    perror("raw socket created error");
    exit(1);
    }

    setuid(getuid());
    pid = getpid();

    set_sighandler();
    printf("Ping %s(%s): %d bytes data in ICMP packets. ",
    argv[1], inet_ntoa(dest.sin_addr), datalen);

    if ((setitimer(ITIMER_REAL, &val_alarm, NULL)) == -1)
    bail("setitimer fails.");


    recv_reply();

    return 0;
    }

    void send_ping(void)
    {
    struct icmphdr *icmp_hdr;
    int len;

    icmp_hdr = (struct icmphdr *)sendbuf;
    icmp_hdr->type = ICMP_ECHO;
    icmp_hdr->code = 0;
    icmp_hdr->icmp_id = pid;
    icmp_hdr->icmp_seq = nsent++;
    memset(icmp_hdr->data, 0xff, datalen);

    gettimeofday((struct timeval *)icmp_hdr->data, NULL);

    len = ICMP_HSIZE + datalen;
    icmp_hdr->checksum = 0;
    icmp_hdr->checksum = checksum((u8 *)icmp_hdr, len);

    sendto(sockfd, sendbuf, len, 0, (struct sockaddr *)&dest, sizeof(dest));
    }

    void recv_reply()
    {
    int n, len;
    int errno;

    n = nrecv = 0;
    len = sizeof(from);

    while (nrecv < 3){
    if ((n = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&from, &len)) < 0){
    if (errno == EINTR)
    continue;
    bail("recvfrom error");
    }

    gettimeofday(&recvtime, NULL);

    if (handle_pkt())

    continue;
    nrecv++;
    }

    get_statistics(nsent, nrecv);
    }

    u16 checksum(u8 *buf, int len)
    {
    u32 sum = 0;
    u16 *cbuf;

    cbuf = (u16 *)buf;

    while (len > 1){
    sum += *cbuf++;
    len -= 2;
    }

    if(len)
    sum += *(u8 *)cbuf;

    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);

    return -sum;
    }


    int handle_pkt()
    {
    struct iphdr *ip;
    struct icmphdr *icmp;

    int ip_hlen;
    u16 ip_datalen;
    double rtt;
    struct timeval *sendtime;

    ip = (struct iphdr *)recvbuf;

    ip_hlen = ip->hlen << 2;
    ip_datalen = ntohs(ip->tot_len) - ip_hlen;

    icmp = (struct icmphdr *)(recvbuf + ip_hlen);

    if (checksum(u8 *)icmp, ip_datalen)
    return -1;


    if(icmp->icmp_id != pid)
    return -1;

    sendtime = (struct timeval *)icmp->data;
    rtt = ((&recvtime)->tv_sec - sendtime->tv_sec)*1000 + ((&recvtime)->tv_usec - sendtime->tv_usec)/1000.0;

    printf("%d bytes from %s: icmp_seq = %u ttl=%d rtt=%.3f ms ",
    ip_datalen,
    inet_ntoa(from.sin_addr),
    icmp->icmp_seq,
    ip->ttl,
    rtt);

    return 0;
    }

    void set_sighandler()
    {
    act_alarm.sa_handler = alarm_handler;
    if (sigaction(SIGALRM, &act_alarm, NULL) == -1)
    bail("SIGALRM handler setting fails.");

    act_int.sa_handler = int_handler;
    if (sigaction(SIGINT, &act_int, NULL) == -1)
    bail("SIGINT handler setting fails.");
    }

    void get_statistics(int nsent, int nrecv)
    {
    printf("---%s ping statistics --- ", inet_ntoa(dest.sin_addr));
    printf("%d packets transmitted, %d received, %0.0f%%" "packet loss ",
    nsent, nrecv, 1.0*(nsent - nrecv)/nsent*100);
    }

    void bail(const char *on_what)
    {
    fputs(strerror(errno), stderr);
    fputs(":", stderr);
    fputs(on_what, stderr);
    fputc(' ', stderr);
    exit(1);
    }


    void int_handler(int sig)
    {
    get_statistics(nsent, nrecv);
    close(sockfd);
    exit(1);
    }


    void alarm_handler(int signo)
    {
    send_ping();
    }

  • 相关阅读:
    如何使Linux系统上的程序开机后自动运行 (转)
    Makefile详解 (转--不错就是有点长)
    ./configure && make && make install详解 (转)
    从程序员角度看ELF | Linux-Programming (转)
    动态符号链接的细节 (转)
    GCC编译动态和静态链接库例子
    gcc编译静态库和动态库
    udhcp源码详解(五) 之DHCP包--options字段
    一个炒鸡好用的pdf阅读器
    Linux 创建用户 用户组 用户权限
  • 原文地址:https://www.cnblogs.com/wolflion/p/3345850.html
Copyright © 2020-2023  润新知