| http://openwall.info/wiki/people/segoon/ping |
| |
| --- iputils-s20101006/ping.c |
| +++ iputils-s20101006/ping.c |
| @@ -88,6 +88,7 @@ struct sockaddr_in whereto; /* who to pi |
| int optlen = 0; |
| int settos = 0; /* Set TOS, Precendence or other QOS options */ |
| int icmp_sock; /* socket file descriptor */ |
| +int using_ping_socket = 0; |
| u_char outpack[0x10000]; |
| int maxpacket = sizeof(outpack); |
| |
| @@ -123,7 +124,11 @@ main(int argc, char **argv) |
| char *target, hnamebuf[MAX_HOSTNAMELEN]; |
| char rspace[3 + 4 * NROUTES + 1]; /* record route space */ |
| |
| - icmp_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); |
| + icmp_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); |
| + if (icmp_sock != -1) |
| + using_ping_socket = 1; |
| + else |
| + icmp_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); |
| socket_errno = errno; |
| |
| uid = getuid(); |
| @@ -377,13 +382,35 @@ main(int argc, char **argv) |
| } |
| } |
| |
| - if ((options&F_STRICTSOURCE) && |
| - bind(icmp_sock, (struct sockaddr*)&source, sizeof(source)) == -1) { |
| - perror("bind"); |
| - exit(2); |
| + if (!using_ping_socket) { |
| + if ((options&F_STRICTSOURCE) && |
| + bind(icmp_sock, (struct sockaddr*)&source, sizeof(source)) == -1) { |
| + perror("bind"); |
| + exit(2); |
| + } |
| + } else { |
| + struct sockaddr_in sa; |
| + socklen_t sl; |
| + |
| + sa.sin_family = AF_INET; |
| + sa.sin_port = 0; |
| + sa.sin_addr.s_addr = (options&F_STRICTSOURCE) ? |
| + source.sin_addr.s_addr : 0; |
| + sl = sizeof(sa); |
| + |
| + if (bind(icmp_sock, (struct sockaddr *) &sa, sl) == -1) { |
| + perror("bind"); |
| + exit(2); |
| + } |
| + |
| + if (getsockname(icmp_sock, (struct sockaddr *) &sa, &sl) == -1) { |
| + perror("getsockname"); |
| + exit(2); |
| + } |
| + ident = sa.sin_port; |
| } |
| |
| - if (1) { |
| + if (!using_ping_socket) { |
| struct icmp_filter filt; |
| filt.data = ~((1<<ICMP_SOURCE_QUENCH)| |
| (1<<ICMP_DEST_UNREACH)| |
| @@ -398,6 +425,12 @@ main(int argc, char **argv) |
| hold = 1; |
| if (setsockopt(icmp_sock, SOL_IP, IP_RECVERR, (char *)&hold, sizeof(hold))) |
| fprintf(stderr, "WARNING: your kernel is veeery old. No problems.\n"); |
| + if (using_ping_socket) { |
| + if (setsockopt(icmp_sock, SOL_IP, IP_RECVTTL, (char *)&hold, sizeof(hold))) |
| + perror("WARNING: setsockopt(IP_RECVTTL)"); |
| + if (setsockopt(icmp_sock, SOL_IP, IP_RETOPTS, (char *)&hold, sizeof(hold))) |
| + perror("WARNING: setsockopt(IP_RETOPTS)"); |
| + } |
| |
| /* record route option */ |
| if (options & F_RROUTE) { |
| @@ -566,6 +599,7 @@ int receive_error_msg() |
| nerrors++; |
| } else if (e->ee_origin == SO_EE_ORIGIN_ICMP) { |
| struct sockaddr_in *sin = (struct sockaddr_in*)(e+1); |
| + int error_pkt; |
| |
| if (res < sizeof(icmph) || |
| target.sin_addr.s_addr != whereto.sin_addr.s_addr || |
| @@ -576,9 +610,18 @@ int receive_error_msg() |
| goto out; |
| } |
| |
| - acknowledge(ntohs(icmph.un.echo.sequence)); |
| + error_pkt = (e->ee_type != ICMP_REDIRECT && |
| + e->ee_type != ICMP_SOURCE_QUENCH); |
| + if (error_pkt) { |
| + acknowledge(ntohs(icmph.un.echo.sequence)); |
| + net_errors++; |
| + nerrors++; |
| + } |
| + else { |
| + saved_errno = 0; |
| + } |
| |
| - if (!working_recverr) { |
| + if (!using_ping_socket && !working_recverr) { |
| struct icmp_filter filt; |
| working_recverr = 1; |
| /* OK, it works. Add stronger filter. */ |
| @@ -589,15 +632,14 @@ int receive_error_msg() |
| perror("\rWARNING: setsockopt(ICMP_FILTER)"); |
| } |
| |
| - net_errors++; |
| - nerrors++; |
| if (options & F_QUIET) |
| goto out; |
| if (options & F_FLOOD) { |
| - write_stdout("\bE", 2); |
| + if (error_pkt) |
| + write_stdout("\bE", 2); |
| } else { |
| print_timestamp(); |
| - printf("From %s icmp_seq=%u ", pr_addr(sin->sin_addr.s_addr), ntohs(icmph.un.echo.sequence)); |
| + printf("From %s: icmp_seq=%u ", pr_addr(sin->sin_addr.s_addr), ntohs(icmph.un.echo.sequence)); |
| pr_icmph(e->ee_type, e->ee_code, e->ee_info, NULL); |
| fflush(stdout); |
| } |
| @@ -695,15 +737,41 @@ parse_reply(struct msghdr *msg, int cc, |
| struct iphdr *ip; |
| int hlen; |
| int csfailed; |
| + struct cmsghdr *cmsg; |
| + int ttl; |
| + __u8 *opts; |
| + int optlen; |
| |
| /* Check the IP header */ |
| ip = (struct iphdr *)buf; |
| - hlen = ip->ihl*4; |
| - if (cc < hlen + 8 || ip->ihl < 5) { |
| - if (options & F_VERBOSE) |
| - fprintf(stderr, "ping: packet too short (%d bytes) from %s\n", cc, |
| - pr_addr(from->sin_addr.s_addr)); |
| - return 1; |
| + if (!using_ping_socket) { |
| + hlen = ip->ihl*4; |
| + if (cc < hlen + 8 || ip->ihl < 5) { |
| + if (options & F_VERBOSE) |
| + fprintf(stderr, "ping: packet too short (%d bytes) from %s\n", cc, |
| + pr_addr(from->sin_addr.s_addr)); |
| + return 1; |
| + } |
| + ttl = ip->ttl; |
| + opts = buf + sizeof(struct iphdr); |
| + optlen = hlen - sizeof(struct iphdr); |
| + } else { |
| + hlen = 0; |
| + ttl = 0; |
| + opts = buf; |
| + optlen = 0; |
| + for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { |
| + if (cmsg->cmsg_level != SOL_IP) |
| + continue; |
| + if (cmsg->cmsg_type == IP_TTL) { |
| + if (cmsg->cmsg_len < sizeof(int)) |
| + continue; |
| + ttl = *(int *) CMSG_DATA(cmsg); |
| + } else if (cmsg->cmsg_type == IP_RETOPTS) { |
| + opts = (__u8 *) CMSG_DATA(cmsg); |
| + optlen = cmsg->cmsg_len; |
| + } |
| + } |
| } |
| |
| /* Now the ICMP part */ |
| @@ -716,7 +784,7 @@ parse_reply(struct msghdr *msg, int cc, |
| return 1; /* 'Twas not our ECHO */ |
| if (gather_statistics((__u8*)icp, sizeof(*icp), cc, |
| ntohs(icp->un.echo.sequence), |
| - ip->ttl, 0, tv, pr_addr(from->sin_addr.s_addr), |
| + ttl, 0, tv, pr_addr(from->sin_addr.s_addr), |
| pr_echo_reply)) |
| return 0; |
| } else { |
| @@ -807,7 +875,7 @@ parse_reply(struct msghdr *msg, int cc, |
| } |
| |
| if (!(options & F_FLOOD)) { |
| - pr_options(buf + sizeof(struct iphdr), hlen); |
| + pr_options(opts, optlen + sizeof(struct iphdr)); |
| |
| if (options & F_AUDIBLE) |
| putchar('\a'); |
| @@ -916,8 +984,7 @@ void pr_icmph(__u8 type, __u8 code, __u3 |
| printf("Redirect, Bad Code: %d", code); |
| break; |
| } |
| - if (icp) |
| - printf("(New nexthop: %s)\n", pr_addr(icp->un.gateway)); |
| + printf("(New nexthop: %s)\n", pr_addr(icp ? icp->un.gateway : info)); |
| if (icp && (options & F_VERBOSE)) |
| pr_iph((struct iphdr*)(icp + 1)); |
| break; |
| @@ -1217,7 +1284,7 @@ void install_filter(void) |
| insns |
| }; |
| |
| - if (once) |
| + if (once || using_ping_socket) |
| return; |
| once = 1; |
| |
| --- iputils-s20101006/ping_common.c |
| +++ iputils-s20101006/ping_common.c |
| @@ -515,7 +515,8 @@ void setup(int icmp_sock) |
| *p++ = i; |
| } |
| |
| - ident = htons(getpid() & 0xFFFF); |
| + if (!ident) |
| + ident = htons(getpid() & 0xFFFF); |
| |
| set_signal(SIGINT, sigexit); |
| set_signal(SIGALRM, sigexit); |