From patchwork Thu Jun 9 16:44:19 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vasiliy Kulikov X-Patchwork-Id: 99782 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 5DFF7B6FE5 for ; Fri, 10 Jun 2011 02:44:28 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752709Ab1FIQoY (ORCPT ); Thu, 9 Jun 2011 12:44:24 -0400 Received: from mail-fx0-f46.google.com ([209.85.161.46]:57341 "EHLO mail-fx0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750959Ab1FIQoW (ORCPT ); Thu, 9 Jun 2011 12:44:22 -0400 Received: by fxm17 with SMTP id 17so1106757fxm.19 for ; Thu, 09 Jun 2011 09:44:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:sender:date:from:to:cc:subject:message-id :mime-version:content-type:content-disposition:user-agent; bh=b9ItPYkDa+NZLIN6CyeKRDqZSnq3eCpmBEiHZ+GHRj0=; b=BHlzFk7MIsY93Lqbnjn+600y87egQMiHyECo7ltl8P74o+9kqhrsXf4x062LkOMCgy s3ZoRCKrQCeQezofNGHqlRUdCBJcrP4ZhnEoaUpQ7gfYYOp9RvNYaia7/5/SxNFXjqey CprDh6mveiSbn9t9ajVw4nk7W2oWcqytljuiE= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=sender:date:from:to:cc:subject:message-id:mime-version:content-type :content-disposition:user-agent; b=SGjjeG8S/nnvoJkMbmsOdAey6GUesDyBkm7Van8v4KV3bGwCWXjWVZrMf/9EcCZ8H+ K9Pv2GhiAUlj7Ws8DwNkbOvtyKy//l6bFGx32JYWDrjCGWgb60wi3q20GmnA8wJ5239w 2MsIF7oLAzYKGLulM6dB8aJwDYultB1XDsguE= Received: by 10.223.17.68 with SMTP id r4mr1046499faa.62.1307637861222; Thu, 09 Jun 2011 09:44:21 -0700 (PDT) Received: from localhost (ppp85-140-8-171.pppoe.mtu-net.ru [85.140.8.171]) by mx.google.com with ESMTPS id l26sm731417fah.14.2011.06.09.09.44.18 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 09 Jun 2011 09:44:20 -0700 (PDT) Date: Thu, 9 Jun 2011 20:44:19 +0400 From: Vasiliy Kulikov To: netdev@vger.kernel.org Cc: Pavel Kankovsky , Solar Designer Subject: [patch] iputils ping: add icmp socket support Message-ID: <20110609164419.GA29454@albatros> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.20 (2009-06-14) Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This patch adds nonraw IPPROTO_ICMP socket kind support that was added to the Linux 3.0. The patch is backward-compatible: if icmp socket kind is not enabled in the kernel (either in case of an old kernel or explicitly disabled via /proc/sys/net/ipv4/ping_group_range), ping uses old privileged raw sockets as a fallback. The distributions are free to choose whether ping binary is setgid and owned by a special group or is just a normal binary. The patch is used in Owl-current since February (Owl-current had ping sockets support before the mainline). Signed-off-by: Vasiliy Kulikov --- -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff -uNp -r iputils-s20101006.orig/ping.c iputils-s20101006/ping.c --- iputils-s20101006.orig/ping.c 2010-10-06 11:59:20 +0000 +++ iputils-s20101006/ping.c 2011-03-24 12:21:30 +0000 @@ -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<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_FILENO, "\bE", 2); + if (error_pkt) + write(STDOUT_FILENO, "\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; diff -uNp -r iputils-s20101006.orig/ping_common.c iputils-s20101006/ping_common.c --- iputils-s20101006.orig/ping_common.c 2010-10-06 11:59:20 +0000 +++ iputils-s20101006/ping_common.c 2011-03-24 12:22:20 +0000 @@ -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);