📄 ping.c
字号:
if (inet_ntop(family, (family == AF_INET) ? (const void *) (&(((struct sockaddr_in *)&from)->sin_addr)) : (const void *) (&(((struct sockaddr_in6 *)&from)->sin6_addr)), from_str, sizeof(from_str)) == NULL) { PRINTF("Could not convert source address.\n"); err = -1; break; } /* * Interpret the ICMP status and output response accordingly. * Extend to suit requirements. For example, a lookup table * would be a far more efficient and extensible approach - * this codes implemented here are just for reference and * represent some likely outcomes for a failed ping. * The rest just have a default handler that outputs the * ICMP type and code. */ if (family == AF_INET) { struct icmp *p_icmphdr; struct ipheader *p_iphdr; int ip_hdr_size; /* Get seperate pointers to ICMP and IP headers */ p_iphdr = (struct ipheader *)(p_buf); ip_hdr_size = 4 * IP_GET_IHL(p_iphdr); p_icmphdr = (struct icmp *)(p_buf + ip_hdr_size); /* Adjust received length to not count the IP header */ len = status - ip_hdr_size; if (p_icmphdr->icmp_type != ICMP_ECHOREPLY) { switch (p_icmphdr->icmp_type) { case ICMP_UNREACH: switch( p_icmphdr->icmp_code ) { case ICMP_UNREACH_NET: PRINTF("%s reports destination net " "unreachable.\n", from_str); break; case ICMP_UNREACH_HOST: PRINTF("%s reports destination host " "unreachable.\n", from_str); break; case ICMP_UNREACH_PORT: PRINTF("%s reports destination port " "unreachable.\n", from_str); break; case ICMP_UNREACH_NEEDFRAG: PRINTF("%s reports destination " "unreachable - fragmentation " "required but don't-fragment " "set.\n", from_str); break; default: PRINTF("%s reports destination " "unreachable: code %d.\n", from_str, p_icmphdr->icmp_code); break; } /* choose vaguely sensible error code */ err = EHOSTUNREACH; break; case ICMP_TIMXCEED: PRINTF("%s reports time-to-live exceeded " "(with code %d).\n", from_str, p_icmphdr->icmp_code); /* choose vaguely sensible error code */ err = EHOSTUNREACH; break; case ICMP_PARAMPROB: PRINTF("%s reports parameter problem " "(with code %d).\n", from_str, p_icmphdr->icmp_code); /* choose vaguely sensible error code */ err = EHOSTUNREACH; break; case ICMP_ECHO: /* * We might see our own echo request * in some cases */ if (p_icmphdr->icmp_id != fd) { PRINTF("ICMP echo request from %s.\n", from_str); } break; default: PRINTF("ICMP response from %s, type %d, " "code %d.\n", from_str, p_icmphdr->icmp_type, p_icmphdr->icmp_code); } if (err != 0) { break; } } /* ignore other people's echo replies */ else if (p_icmphdr->icmp_id == fd) { /* Output the result */ roundtrip = (time_recv.tv_sec * 1000) + (time_recv.tv_usec / 1000 ); /* * Granularity of timer means that a round trip * time < 10ms won't show up accurately */ PRINTF("%d bytes from %s: seq=%u, ttl=%d, rtt%s%ldms\n", len, from_str, p_icmphdr->icmp_seq, p_iphdr->ttl, (roundtrip >= 10) ? "=" : "<", (roundtrip >= 10) ? roundtrip : 10); break; } } else { /* Pointer to ICMPv6 headers */ struct icmp6_hdr *p_icmp6hdr = (struct icmp6_hdr *)p_buf; /* Check ICMP6 message type */ if (p_icmp6hdr->icmp6_type != ICMP6_ECHO_REPLY) { switch (p_icmp6hdr->icmp6_type) { case ICMP6_DST_UNREACH: switch (p_icmp6hdr->icmp6_code) { case ICMP6_DST_UNREACH_NOROUTE: PRINTF("%s reports no route to " "destination.\n", from_str); break; case ICMP6_DST_UNREACH_ADMIN: PRINTF("%s reports communication " "with destination administrative " "prohibited.\n", from_str); break; case ICMP6_DST_UNREACH_BEYONDSCOPE: PRINTF("%s reports destination beyond " "scope of source address %s.\n", from_str); break; case ICMP6_DST_UNREACH_ADDR: PRINTF("%s reports destination " "address %s unreachable.\n", from_str, to_str); break; default: PRINTF("%s reports destination " "unreachable: code %d.\n", from_str, p_icmp6hdr->icmp6_code); break; } /* choose vaguely sensible error code */ err = EHOSTUNREACH; break; case ICMP6_PACKET_TOO_BIG: PRINTF("%s reports packet too big " "(with code %d).\n", from_str, p_icmp6hdr->icmp6_code); /* choose vaguely sensible error code */ err = EHOSTUNREACH; break; case ICMP6_TIME_EXCEEDED: switch (p_icmp6hdr->icmp6_code) { case ICMP6_TIME_EXCEED_TRANSIT: PRINTF("%s reports hop limit exceeded.\n", from_str); break; default: PRINTF("%s reports time exceeded: " "code %d.\n", from_str, p_icmp6hdr->icmp6_code); break; } /* choose vaguely sensible error code */ err = EHOSTUNREACH; break; case ICMP6_PARAM_PROB: PRINTF("%s reports parameter problem " "(with code %d).\n", from_str, p_icmp6hdr->icmp6_code); /* choose vaguely sensible error code */ err = EHOSTUNREACH; break; case ICMP6_ECHO_REQUEST: /* * We might see our own echo request * in some cases */ if (p_icmp6hdr->icmp6_id != fd) { PRINTF("ICMP echo request from %s.\n", from_str); } break; default: /* Print only errors, skip informational */ if (!(p_icmp6hdr->icmp6_type & ICMP6_INFOMSG_MASK)) { PRINTF("ICMP response from %s, type %d, " "code %d.\n", from_str, p_icmp6hdr->icmp6_type, p_icmp6hdr->icmp6_code); } } if (err != 0) { break; } } /* Ignore other people's echo replies */ else if (p_icmp6hdr->icmp6_id == fd) { /* Output the result */ roundtrip = (time_recv.tv_sec * 1000) + (time_recv.tv_usec / 1000); /* * Granularity of timer means that a round trip * time < 10ms won't show up accurately */ PRINTF("%d bytes from %s: seq=%u, rtt%s%ldms\n", len, from_str, p_icmp6hdr->icmp6_seq, (roundtrip >= 10) ? "=" : "<", (roundtrip >= 10) ? roundtrip : 10); break; } } } /* End forever loop */ } /* End attempts loop */ /* Close Raw IPv6 socket */ close(fd); /* Free memory allocated for buffer */ free(pkt); return err; } /* do_ping6_v4_v6 *//* in_cksum -- * Checksum routine for Internet Protocol family headers (C Version). * Very dumb, but good enough for ping. * * PARAMETERS: * addr - first address of the buffer with data * len - length of the data in buffer * * RETURNS: * icmp checksum value */u_shortin_cksum(u_short *addr, int len){ register int nleft = len; register u_short *w = addr; register int sum = 0; u_short 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. */ for (nleft = len; nleft > 1; nleft -= 2) { sum += *w++; } /* Mop up an odd byte, if necessary */ if (nleft == 1) { *(u_char *)(&answer) = *(u_char *)w ; sum += answer; } /* Add 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);} /* in_cksum *//* ping_prepare_packet -- * prepares protocol specific (PF_INET or PF_INET6) ICMP echo * request with payload (see PING_EXTRA_DATA_LEN and * PING_EXTRA_DATA_FIRST_VALUE definitions). * * PARAMETERS: * family - protocol family * fd - opened socket (used as request ID) * p_buf - pointer to buffer prepared for packet * p_buf_len - prepared buffer length on input and used buffer * length on output * * RETURNS: * ESUCCESS - success * EINVAL - prepared buffer too small or unknown protocol family */static intping_prepare_packet(int family, int fd, char *p_buf, int *p_buf_len){ /* Length of ICMP header */ int hdr_len = (family == AF_INET) ? sizeof(struct icmphdr) : sizeof(struct icmp6_hdr); /* Total length of the ICMP header and payload */ int total_len = hdr_len + PING_EXTRA_DATA_LEN; int i; /* Check if message fit in prepared buffer */ if (*p_buf_len < total_len) { return EINVAL; } /* * Paint a numeric pattern in the data portion of the packet, * so we can verify in a traffic monitor */ for (i = 0; i < PING_EXTRA_DATA_LEN; i++) { p_buf[i + hdr_len] = PING_EXTRA_DATA_FIRST_VALUE + i; } if (family == PF_INET) { struct icmp *p_icmphdr = (struct icmp *)p_buf; p_icmphdr->icmp_type = ICMP_ECHO; p_icmphdr->icmp_code = 0; p_icmphdr->icmp_cksum = 0; /* Calculated and inserted below */ p_icmphdr->icmp_seq = 0; p_icmphdr->icmp_id = fd; p_icmphdr->icmp_cksum = in_cksum((ushort *)p_icmphdr, total_len); } else if (family == PF_INET6) { struct icmp6_hdr *p_icmp6hdr = (struct icmp6_hdr *)p_buf; p_icmp6hdr->icmp6_type = ICMP6_ECHO_REQUEST; p_icmp6hdr->icmp6_code = 0; p_icmp6hdr->icmp6_cksum = 0; /* Calculated and inserted by kernel */ p_icmp6hdr->icmp6_seq = 0; p_icmp6hdr->icmp6_id = fd; } else { return EINVAL; } /* Return used length of the buffer */ *p_buf_len = total_len; return ESUCCESS; } /* ping_prepare_packet *//* tv_sub -- * Subtract timeval "in" from "out", adjust value of "out" * with result. * * PARAMETERS: * out - minuend and difference * in - subtrahend * * RETURNS: * -- */voidtv_sub(struct timeval *out, struct timeval *in){ if ((out->tv_usec -= in->tv_usec) < 0) { --out->tv_sec; out->tv_usec += 1000000; } out->tv_sec -= in->tv_sec;} /* tv_sub */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -