📄 ping6.c
字号:
timing++; tp = (struct timeval *) icmp6 + 1; /* Avoid unaligned data: */ memcpy (&tv1, tp, sizeof (tv1)); tvsub (&tv, &tv1); triptime = ((double)tv.tv_sec) * 1000.0 + ((double)tv.tv_usec) / 1000.0; ping_stat->tsum += triptime; ping_stat->tsumsq += triptime*triptime; if (triptime < ping_stat->tmin) ping_stat->tmin = triptime; if (triptime > ping_stat->tmax) ping_stat->tmax = triptime; } if (options & OPT_QUIET) return 0; if (options & OPT_FLOOD) { putchar ('\b'); return 0; } err = getnameinfo ((struct sockaddr *) from, sizeof (*from), buf, sizeof (buf), NULL, 0, 0); if (err) { const char *errmsg; if (err == EAI_SYSTEM) errmsg = strerror (errno); else errmsg = gai_strerror (err); fprintf (stderr, "ping: getnameinfo: %s\n", errmsg); strcpy (buf, "unknown"); } printf ("%d bytes from %s: icmp_seq=%u", datalen, buf, htons (icmp6->icmp6_seq)); if (hops >= 0) printf (" ttl=%d", hops); if (timing) printf (" time=%.3f ms", triptime); if (dupflag) printf (" (DUP!)"); putchar ('\n'); return 0;}#define NITEMS(a) sizeof(a)/sizeof((a)[0])struct icmp_code_descr { int code; char *diag;};static struct icmp_code_descr icmp_dest_unreach_desc[] = { { ICMP6_DST_UNREACH_NOROUTE, "No route to destination" }, { ICMP6_DST_UNREACH_ADMIN, "Destination administratively prohibited" }, { ICMP6_DST_UNREACH_BEYONDSCOPE, "Beyond scope of source address" }, { ICMP6_DST_UNREACH_ADDR, "Address unreachable" }, { ICMP6_DST_UNREACH_NOPORT, "Port unreachable" },};static voidprint_dst_unreach (struct icmp6_hdr *icmp6){ struct icmp_code_descr *p; printf ("Destination unreachable: "); for (p = icmp_dest_unreach_desc; p < icmp_dest_unreach_desc + NITEMS(icmp_dest_unreach_desc); p++) { if (p->code == icmp6->icmp6_code) { puts (p->diag); return; } } printf ("Unknown code %d\n", icmp6->icmp6_code);}static voidprint_packet_too_big (struct icmp6_hdr *icmp6){ printf ("Packet too big, mtu=%d\n", icmp6->icmp6_mtu);}static struct icmp_code_descr icmp_time_exceeded_desc[] = { { ICMP6_TIME_EXCEED_TRANSIT, "Hop limit exceeded"}, { ICMP6_TIME_EXCEED_REASSEMBLY, "Fragment reassembly timeout"},};static voidprint_time_exceeded (struct icmp6_hdr *icmp6){ struct icmp_code_descr *p; printf ("Time exceeded: "); for (p = icmp_time_exceeded_desc; p < icmp_time_exceeded_desc + NITEMS(icmp_time_exceeded_desc); p++) { if (p->code == icmp6->icmp6_code) { puts (p->diag); return; } } printf ("Unknown code %d\n", icmp6->icmp6_code);}static struct icmp_code_descr icmp_param_prob_desc[] = { { ICMP6_PARAMPROB_HEADER, "Erroneous header field"}, { ICMP6_PARAMPROB_NEXTHEADER, "Unrecognized Next Header type"}, { ICMP6_PARAMPROB_OPTION, "Unrecognized IPv6 option"},};static voidprint_param_prob (struct icmp6_hdr *icmp6){ struct icmp_code_descr *p; printf ("Parameter problem: "); for (p = icmp_param_prob_desc; p < icmp_param_prob_desc + NITEMS(icmp_param_prob_desc); p++) { if (p->code == icmp6->icmp6_code) { puts (p->diag); return; } } printf ("Unknown code %d\n", icmp6->icmp6_code);}static struct icmp_diag { int type; void (*func) (struct icmp6_hdr *);} icmp_diag[] = { { ICMP6_DST_UNREACH, print_dst_unreach }, { ICMP6_PACKET_TOO_BIG, print_packet_too_big }, { ICMP6_TIME_EXCEEDED, print_time_exceeded }, { ICMP6_PARAM_PROB, print_param_prob },};static voidprint_icmp_error (struct sockaddr_in6 *from, struct icmp6_hdr *icmp6, int len){ char *s; struct icmp_diag *p; s = ipaddr2str (from); printf ("%d bytes from %s: ", len, s); free (s); for (p = icmp_diag; p < icmp_diag + NITEMS(icmp_diag); p++) { if (p->type == icmp6->icmp6_type) { p->func (icmp6); return; } } /* This should never happen because of the ICMP6_FILTER set in ping_init(). */ printf ("Unknown ICMP type: %d\n", icmp6->icmp6_type);}static intecho_finish (){ ping_finish (); if (ping->ping_num_recv && PING_TIMING (data_length)) { struct ping_stat *ping_stat = (struct ping_stat*)ping->ping_closure; double total = ping->ping_num_recv + ping->ping_num_rept; double avg = ping_stat->tsum/total; double vari = ping_stat->tsumsq / total - avg * avg; printf ("round-trip min/avg/max/stddev = %.3f/%.3f/%.3f/%.3f ms\n", ping_stat->tmin, avg, ping_stat->tmax, nsqrt (vari, 0.0005)); } exit (ping->ping_num_recv == 0);}static voidshow_usage (void){ printf ("\Usage: ping6 [OPTION]... [ADDRESS]...\n\\n\Informational options:\n\ -h, --help display this help and exit\n\ -L, --license display license and exit\n\ -V, --version output version information and exit\n\Options valid for all request types:\n\ -c, --count N stop after sending N packets\n\ -d, --debug set the SO_DEBUG option\n\ -i, --interval N wait N seconds between sending each packet\n\ -n, --numeric do not resolve host addresses\n\ -r, --ignore-routing send directly to a host on an attached network\n\Options valid for --echo requests:\n\* -f, --flood flood ping \n\* -l, --preload N send N packets as fast as possible before falling into\n\ normal mode of behavior\n\ -p, --pattern PAT fill ICMP packet with given pattern (hex)\n\ -q, --quiet quiet output\n\ -s, --size N set number of data octets to send\n\\n\Options marked with an * are available only to super-user\n\\n\report bugs to " PACKAGE_BUGREPORT ".\n\");}static PING *ping_init (int type, int ident){ int fd, err; const int on = 1; PING *p; struct icmp6_filter filter; /* Initialize raw ICMPv6 socket */ fd = socket (PF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (fd < 0) { if (errno == EPERM) { fprintf (stderr, "ping: ping must run as root\n"); } return NULL; } /* Tell which ICMPs we are interested in. */ ICMP6_FILTER_SETBLOCKALL (&filter); ICMP6_FILTER_SETPASS (ICMP6_ECHO_REPLY, &filter); ICMP6_FILTER_SETPASS (ICMP6_DST_UNREACH, &filter); ICMP6_FILTER_SETPASS (ICMP6_PACKET_TOO_BIG, &filter); ICMP6_FILTER_SETPASS (ICMP6_TIME_EXCEEDED, &filter); ICMP6_FILTER_SETPASS (ICMP6_PARAM_PROB, &filter); err = setsockopt (fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof (filter)); if (err) { close (fd); return NULL; } err = setsockopt (fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof (on)); if (err) { close (fd); return NULL; } /* Allocate PING structure and initialize it to default values */ p = malloc (sizeof (*p)); if (!p) { close (fd); return NULL; } memset (p, 0, sizeof (*p)); p->ping_fd = fd; p->ping_count = 0; p->ping_interval = PING_INTERVAL; p->ping_datalen = sizeof (struct icmp6_hdr); /* Make sure we use only 16 bits in this field, id for icmp is a u_short. */ p->ping_ident = ident & 0xFFFF; p->ping_cktab_size = PING_CKTABSIZE; return p;}static int_ping_setbuf (PING *p){ if (!p->ping_buffer) { p->ping_buffer = malloc (_PING_BUFLEN (p)); if (!p->ping_buffer) return -1; } if (!p->ping_cktab) { p->ping_cktab = malloc (p->ping_cktab_size); if (!p->ping_cktab) return -1; memset (p->ping_cktab, 0, p->ping_cktab_size); } return 0;}static intping_set_data (PING *p, void *data, size_t off, size_t len){ if (_ping_setbuf (p)) return -1; if (p->ping_datalen < off + len) return -1; memcpy (p->ping_buffer + sizeof (struct icmp6_hdr) + off, data, len); return 0;}static intping_xmit (PING *p){ int i, buflen; struct icmp6_hdr *icmp6; if (_ping_setbuf (p)) return -1; buflen = p->ping_datalen + sizeof (struct icmp6_hdr); /* Mark sequence number as sent */ _PING_CLR (p, p->ping_num_xmit % p->ping_cktab_size); icmp6 = (struct icmp6_hdr *) p->ping_buffer; icmp6->icmp6_type = ICMP6_ECHO_REQUEST; icmp6->icmp6_code = 0; /* The checksum will be calculated by the TCP/IP stack. */ icmp6->icmp6_cksum = 0; icmp6->icmp6_id = htons (p->ping_ident); icmp6->icmp6_seq = htons (p->ping_num_xmit); i = sendto (p->ping_fd, (char *)p->ping_buffer, buflen, 0, (struct sockaddr*) &p->ping_dest, sizeof (p->ping_dest)); if (i < 0) perror ("ping: sendto"); else { p->ping_num_xmit++; if (i != buflen) printf ("ping: wrote %s %d chars, ret=%d\n", p->ping_hostname, buflen, i); } return 0;}static intmy_echo_reply (PING *p, struct icmp6_hdr *icmp6){ struct ip6_hdr *orig_ip = (struct ip6_hdr *) (icmp6 + 1); struct icmp6_hdr *orig_icmp = (struct icmp6_hdr *)(orig_ip + 1); return IN6_ARE_ADDR_EQUAL (&orig_ip->ip6_dst, &ping->ping_dest.sin6_addr) && orig_ip->ip6_nxt == IPPROTO_ICMPV6 && orig_icmp->icmp6_type == ICMP6_ECHO_REQUEST && orig_icmp->icmp6_id == htons (p->ping_ident);}static intping_recv (PING *p){ int dupflag, n; int hops = -1; struct msghdr msg; struct iovec iov; struct icmp6_hdr *icmp6; struct cmsghdr *cmsg; char cmsg_data[1024]; iov.iov_base = p->ping_buffer; iov.iov_len = _PING_BUFLEN (p); msg.msg_name = &p->ping_from; msg.msg_namelen = sizeof (p->ping_from); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = cmsg_data; msg.msg_controllen = sizeof (cmsg_data); msg.msg_flags = 0; n = recvmsg (p->ping_fd, &msg, 0); if (n < 0) return -1; for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR (&msg, cmsg)) { if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_HOPLIMIT) { hops = *(int *)CMSG_DATA(cmsg); break; } } icmp6 = (struct icmp6_hdr *) p->ping_buffer; if (icmp6->icmp6_type == ICMP6_ECHO_REPLY) { /* We got an echo reply. */ if (ntohs (icmp6->icmp6_id) != p->ping_ident) return -1; /* It's not a response to us. */ if (_PING_TST (p, ntohs (icmp6->icmp6_seq) % p->ping_cktab_size)) { /* We already got the reply for this echo request. */ p->ping_num_rept++; dupflag = 1; } else { _PING_SET (p, ntohs (icmp6->icmp6_seq) % p->ping_cktab_size); p->ping_num_recv++; dupflag = 0; } print_echo (dupflag, hops, p->ping_closure, &p->ping_dest, &p->ping_from, icmp6, n); } else { /* We got an error reply. */ if (!my_echo_reply (p, icmp6)) return -1; /* It's not for us. */ print_icmp_error (&p->ping_from, icmp6, n); } return 0;}static intping_set_dest (PING *ping, char *host){ int err; struct addrinfo *result, hints; memset (&hints, 0, sizeof (hints)); hints.ai_family = AF_INET6; err = getaddrinfo (host, NULL, &hints, &result); if (err) return 1; memcpy (&ping->ping_dest, result->ai_addr, result->ai_addrlen); freeaddrinfo (result); ping->ping_hostname = strdup (host); if (!ping->ping_hostname) return 1; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -