zoukankan      html  css  js  c++  java
  • Ping

    #include"unp.h"
    #include<netinet/in_systm.h>
    #include<netinet/ip.h>
    #include<netinet/ip_icmp.h>
    #define BUFSIZE 1500
    /*Globals*/
    char sendbuf[BUFSIZE];
    int datalen;
    char *host;
    int nsent; /* add 1 for each sendto() */
    pid_t pid; /* out PID */
    int sockfd;
    int verbose;
    /* function prototype */
    void init_v6(void);
    void proc_v4(char * ,ssize_t,struct msghdr *,struct timeval *);
    void proc_v6(char *, ssize_t,struct msghdr *,struct timeval *);
    void send_v4(void);
    void send_v6(void);
    void readloop(void);
    void sig_alam(int);
    void tv_sub(struct timeval *,struct timeval *);

    struct proto
    {
     void (*fproc)(char *,ssize_t,struct msghdr *,struct timeval *);
     void (*fsend)(void);
     void (*finit)(void);
     struct sockaddr *sasend; /* sockaddr() for send,from getaddrinfo */
     struct sockaddr *sarecv; /* sockaddr() for receving */
     socklen_t salen;  /* length of sockaddr()s*/
     int icmpproto;   /* IPPROTO_XXX value for ICMP */
     
    }*pr;
    #ifdef IPV6

    #include<netinet/ip6.h>
    #include<netinet/icmp6.h>

    #endif

    #define _GNU_SOURCE
    #include <sys/time.h>
    #include <sys/un.h>
    #include <string.h>
    #include <arpa/inet.h>
    #include <signal.h>
    #include <stdarg.h>
    #include <syslog.h>
    #include <errno.h>
    #include <netinet/in_systm.h>
    #include <netinet/ip.h>
    #include <netinet/ip_icmp.h>
    #include <sys/types.h>
    #include <time.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <netdb.h>
    #include <netinet/ip6.h>
    #include <netinet/icmp6.h>

    #define BUFSIZE  1500
    //#define IPV6
    /* globals */
    char sendbuf[BUFSIZE];

    int datalen;   /* # bytes of data following ICMP header */
    char *host;
    int nsent;   /* add 1 for each sendto() */
    pid_t pid;   /* our PID */
    int sockfd;
    int verbose;

    struct proto {
     void (*fproc) (char *, ssize_t, struct msghdr *, struct timeval *);
     void (*fsend) (void);
     void (*finit) (void);
     struct sockaddr *sasend; /* sockaddr{} for send, from getaddrinfo */
     struct sockaddr *sarecv; /* sockaddr{} for receiving */
     socklen_t salen; /* length of sockaddr{}s */
     int icmpproto;  /* IPPROTO_xxx value for ICMP */
    } *pr;

    #define MAXLINE  4096 /* max text line length */
    int daemon_proc;  /* set nonzero by daemon_init() */
    void err_doit(int errnoflag, int level, const char *fmt, va_list ap)
    {
     int errno_save, n;
     char buf[MAXLINE + 1];

     errno_save = errno; /* value caller might want printed */
    #ifdef HAVE_VSNPRINTF
     vsnprintf(buf, MAXLINE, fmt, ap); /* safe */
    #else
     vsprintf(buf, fmt, ap); /* not safe */
    #endif
     n = strlen(buf);
     if (errnoflag)
      snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save));
     strcat(buf, " ");

     if (daemon_proc) {
      syslog(level, "%s", buf);
     } else {
      fflush(stdout); /* in case stdout and stderr are the same */
      fputs(buf, stderr);
      fflush(stderr);
     }
     return;
    }

    void err_quit(const char *fmt, ...)
    {
     va_list ap;

     va_start(ap, fmt);
     err_doit(0, LOG_ERR, fmt, ap);
     va_end(ap);
     exit(1);
    }

    void err_sys(const char *fmt, ...)
    {
     va_list ap;

     va_start(ap, fmt);
     err_doit(1, LOG_ERR, fmt, ap);
     va_end(ap);
     exit(1);
    }

    char *sock_ntop_host(const struct sockaddr *sa, socklen_t salen)
    {
     static char str[128]; /* Unix domain is largest */

     switch (sa->sa_family) {
     case AF_INET:{
       struct sockaddr_in *sin = (struct sockaddr_in *)sa;

       if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str))
           == NULL)
        return (NULL);
       return (str);
      }

    #ifdef IPV6
     case AF_INET6:{
       struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;

       if (inet_ntop
           (AF_INET6, &sin6->sin6_addr, str,
            sizeof(str)) == NULL)
        return (NULL);
       return (str);
      }
    #endif

    #ifdef AF_UNIX
     case AF_UNIX:{
       struct sockaddr_un *unp = (struct sockaddr_un *)sa;

       /* OK to have no pathname bound to the socket: happens on
          every connect() unless client calls bind() first. */
       if (unp->sun_path[0] == 0)
        strcpy(str, "(no pathname bound)");
       else
        snprintf(str, sizeof(str), "%s", unp->sun_path);
       return (str);
      }
    #endif

    #ifdef HAVE_SOCKADDR_DL_STRUCT
     case AF_LINK:{
       struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;

       if (sdl->sdl_nlen > 0)
        snprintf(str, sizeof(str), "%*s",
          sdl->sdl_nlen, &sdl->sdl_data[0]);
       else
        snprintf(str, sizeof(str), "AF_LINK, index=%d",
          sdl->sdl_index);
       return (str);
      }
    #endif
     default:
      snprintf(str, sizeof(str),
        "sock_ntop_host: unknown AF_xxx: %d, len %d",
        sa->sa_family, salen);
      return (str);
     }
     return (NULL);
    }

    char *Sock_ntop_host(const struct sockaddr *sa, socklen_t salen)
    {
     char *ptr;

     if ((ptr = sock_ntop_host(sa, salen)) == NULL)
      err_sys("sock_ntop_host error"); /* inet_ntop() sets errno */
     return (ptr);
    }

    void tv_sub(struct timeval *out, struct timeval *in)
    {
     if ((out->tv_usec -= in->tv_usec) < 0) { /* out -= in */
      --out->tv_sec;
      out->tv_usec += 1000000;
     }
     out->tv_sec -= in->tv_sec;
    }

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

     ip = (struct ip *)ptr; /* start of IP header */
     hlen1 = ip->ip_hl << 2; /* length of IP header */
     if (ip->ip_p != IPPROTO_ICMP)
      return;  /* not ICMP */

     icmp = (struct icmp *)(ptr + hlen1); /* start of ICMP header */
     if ((icmplen = len - hlen1) < 8)
      return;  /* malformed packet */

     if (icmp->icmp_type == ICMP_ECHOREPLY) {
      if (icmp->icmp_id != pid)
       return; /* not a response to our ECHO_REQUEST */
      if (icmplen < 16)
       return; /* not enough data to use */

      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 ",
             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 ",
             icmplen, Sock_ntop_host(pr->sarecv, pr->salen),
             icmp->icmp_type, icmp->icmp_code);
     }
    }

    void Gettimeofday(struct timeval *tv, void *foo)
    {
     if (gettimeofday(tv, foo) == -1)
      err_sys("gettimeofday error");
     return;
    }

    uint16_t in_cksum(uint16_t * addr, int len)
    {
     int nleft = len;
     uint32_t sum = 0;
     uint16_t *w = addr;
     uint16_t answer = 0;

     /*
      * Our algorithm is simple, using a 32 bit accumulator (sum), we add
      * sequential 16 bit words to it, and at the end, fold back all the
      * carry bits from the top 16 bits into the lower 16 bits.
      */
     while (nleft > 1) {
      sum += *w++;
      nleft -= 2;
     }

     /* 4mop up an odd byte, if necessary */
     if (nleft == 1) {
      *(unsigned char *)(&answer) = *(unsigned char *)w;
      sum += answer;
     }

     /* 4add back carry outs from top 16 bits to low 16 bits */
     sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
     sum += (sum >> 16); /* add carry */
     answer = ~sum;  /* truncate to 16 bits */
     return (answer);
    }

    void
    Sendto(int fd, const void *ptr, size_t nbytes, int flags,
           const struct sockaddr *sa, socklen_t salen)
    {
     if (sendto(fd, ptr, nbytes, flags, sa, salen) != (ssize_t) nbytes)
      err_sys("sendto error");
    }

    void send_v4(void)
    {
     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); /* fill with pattern */
     Gettimeofday((struct timeval *)icmp->icmp_data, NULL);

     len = 8 + datalen; /* checksum ICMP header and data */
     icmp->icmp_cksum = 0;
     icmp->icmp_cksum = in_cksum((u_short *) icmp, len);

     Sendto(sockfd, sendbuf, len, 0, pr->sasend, pr->salen);
    }

    int datalen = 56;  /* data that goes with ICMP echo request */

    typedef void Sigfunc(int); /* for signal handlers */
    Sigfunc *signal(int signo, Sigfunc * func)
    {
     struct sigaction act, oact;

     act.sa_handler = func;
     sigemptyset(&act.sa_mask);
     act.sa_flags = 0;
     if (signo == SIGALRM) {
    #ifdef SA_INTERRUPT
      act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */
    #endif
     } else {
    #ifdef SA_RESTART
      act.sa_flags |= SA_RESTART; /* SVR4, 44BSD */
    #endif
     }
     if (sigaction(signo, &act, &oact) < 0)
      return (SIG_ERR);
     return (oact.sa_handler);
    }

    Sigfunc *Signal(int signo, Sigfunc * func)
    {    /* for our signal() function */
     Sigfunc *sigfunc;

     if ((sigfunc = signal(signo, func)) == SIG_ERR)
      err_sys("signal error");
     return (sigfunc);
    }

    struct addrinfo *Host_serv(const char *host, const char *serv, int family,
          int socktype)
    {
     int n;
     struct addrinfo hints, *res;

     bzero(&hints, sizeof(struct addrinfo));
     hints.ai_flags = AI_CANONNAME; /* always return canonical name */
     hints.ai_family = family; /* 0, AF_INET, AF_INET6, etc. */
     hints.ai_socktype = socktype; /* 0, SOCK_STREAM, SOCK_DGRAM, etc. */

     if ((n = getaddrinfo(host, serv, &hints, &res)) != 0)
      err_quit("host_serv error for %s, %s: %s",
        (host == NULL) ? "(no hostname)" : host,
        (serv == NULL) ? "(no service name)" : serv,
        gai_strerror(n));

     return (res);  /* return pointer to first on linked list */
    }

    void *Calloc(size_t n, size_t size)
    {
     void *ptr;

     if ((ptr = calloc(n, size)) == NULL)
      err_sys("calloc error");
     return (ptr);
    }

    void sig_alrm(int signo)
    {
     (*pr->fsend) ();

     alarm(1);
     return;
    }

    int Socket(int family, int type, int protocol)
    {
     int n;

     if ((n = socket(family, type, protocol)) < 0)
      err_sys("socket error");
     return (n);
    }

    void readloop(void)
    {
     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()); /* don't need special permissions any more */
     if (pr->finit)
      (*pr->finit) ();

     size = 60 * 1024; /* OK if setsockopt fails */
     setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));

     sig_alrm(SIGALRM); /* send first packet */

     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
        err_sys("recvmsg error");
      }

      Gettimeofday(&tval, NULL);
      (*pr->fproc) (recvbuf, n, &msg, &tval);
     }
    }

    void proc_v6(char *ptr, ssize_t len, struct msghdr *msg, struct timeval *tvrecv)
    {
    #ifdef IPV6
     double rtt;
     struct icmp6_hdr *icmp6;
     struct timeval *tvsend;
     struct cmsghdr *cmsg;
     int hlim;

     icmp6 = (struct icmp6_hdr *)ptr;
     if (len < 8)
      return;  /* malformed packet */

     if (icmp6->icmp6_type == ICMP6_ECHO_REPLY) {
      if (icmp6->icmp6_id != pid)
       return; /* not a response to our ECHO_REQUEST */
      if (len < 16)
       return; /* not enough data to use */

      tvsend = (struct timeval *)(icmp6 + 1);
      tv_sub(tvrecv, tvsend);
      rtt = tvrecv->tv_sec * 1000.0 + tvrecv->tv_usec / 1000.0;

      hlim = -1;
      for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
           cmsg = CMSG_NXTHDR(msg, cmsg)) {
       if (cmsg->cmsg_level == IPPROTO_IPV6
           && cmsg->cmsg_type == IPV6_HOPLIMIT) {
        hlim = *(u_int32_t *) CMSG_DATA(cmsg);
        break;
       }
      }
      printf("%d bytes from %s: seq=%u, hlim=",
             len, Sock_ntop_host(pr->sarecv, pr->salen),
             icmp6->icmp6_seq);
      if (hlim == -1)
       printf("???"); /* ancillary data missing */
      else
       printf("%d", hlim);
      printf(", rtt=%.3f ms ", rtt);
     } else if (verbose) {
      printf("  %d bytes from %s: type = %d, code = %d ",
             len, Sock_ntop_host(pr->sarecv, pr->salen),
             icmp6->icmp6_type, icmp6->icmp6_code);
     }
    #endif    /* IPV6 */
    }

    void send_v6()
    {
    #ifdef IPV6
     int len;
     struct icmp6_hdr *icmp6;

     icmp6 = (struct icmp6_hdr *)sendbuf;
     icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
     icmp6->icmp6_code = 0;
     icmp6->icmp6_id = pid;
     icmp6->icmp6_seq = nsent++;
     memset((icmp6 + 1), 0xa5, datalen); /* fill with pattern */
     Gettimeofday((struct timeval *)(icmp6 + 1), NULL);

     len = 8 + datalen; /* 8-byte ICMPv6 header */

     Sendto(sockfd, sendbuf, len, 0, pr->sasend, pr->salen);
     /* 4kernel calculates and stores checksum for us */
    #endif    /* IPV6 */
    }

    void init_v6()
    {
    #ifdef IPV6
     int on = 1;

     if (verbose == 0) {
      /* install a filter that only passes ICMP6_ECHO_REPLY unless verbose */
      struct icmp6_filter myfilt;
      ICMP6_FILTER_SETBLOCKALL(&myfilt);
      ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &myfilt);
      setsockopt(sockfd, IPPROTO_IPV6, ICMP6_FILTER, &myfilt,
          sizeof(myfilt));
      /* ignore error return; the filter is an optimization */
     }

     /* ignore error returned below; we just won't receive the hop limit */
    #ifdef IPV6_RECVHOPLIMIT
     /* RFC 3542 */
     setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on));
    #else
     /* RFC 2292 */
     setsockopt(sockfd, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on));
    #endif
    #endif
    }
    struct proto proto_v4 = { proc_v4, send_v4, NULL, NULL, NULL, 0, IPPROTO_ICMP };

    #ifdef IPV6
    struct proto proto_v6 =
        { proc_v6, send_v6, init_v6, NULL, NULL, 0, IPPROTO_ICMPV6 };
    #endif
    int main(int argc, char **argv)
    {
     int c;
     struct addrinfo *ai;
     char *h;

     opterr = 0;  /* don't want getopt() writing to stderr */
     while ((c = getopt(argc, argv, "v")) != -1) {
      switch (c) {
      case 'v':
       verbose++;
       break;

      case '?':
       err_quit("unrecognized option: %c", c);
      }
     }

     if (optind != argc - 1)
      err_quit("usage: ping [ -v ] <hostname>");
     host = argv[optind];

     pid = getpid() & 0xffff; /* ICMP ID field is 16 bits */
     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 ",
            ai->ai_canonname ? ai->ai_canonname : h, h, datalen);

     /* 4initialize according to protocol */
     if (ai->ai_family == AF_INET) {
      pr = &proto_v4;
    #ifdef IPV6
     } else if (ai->ai_family == AF_INET6) {
      pr = &proto_v6;
      if (IN6_IS_ADDR_V4MAPPED(&(((struct sockaddr_in6 *)
             ai->ai_addr)->sin6_addr)))
       err_quit("cannot ping IPv4-mapped IPv6 address");
    #endif
     } else
      err_quit("unknown address family %d", ai->ai_family);

     pr->sasend = ai->ai_addr;
     pr->sarecv = Calloc(1, ai->ai_addrlen);
     pr->salen = ai->ai_addrlen;

     readloop();

     exit(0);
    }

  • 相关阅读:
    BEGIN
    bdflush
    BASH BUILTIN COMMANDS 内建命令
    程序 算法与数据结构
    ThinkPHP 3.2.2 在 volist 多重循环嵌套中使用 if 判断标签
    Java实现 蓝桥杯 算法提高 矩形靶
    Java实现 蓝桥杯 算法提高 矩形靶
    Java实现 蓝桥杯 算法提高 矩形靶
    Java实现 蓝桥杯 算法提高 歌唱比赛
    Java实现 蓝桥杯 算法提高 歌唱比赛
  • 原文地址:https://www.cnblogs.com/liuhg/p/Ping.html
Copyright © 2011-2022 走看看