i've been able to get the SOCK_DGRAM stuff to work with a little help of Vasily, author of the kernel patch.

see attached proof-of-concept patch.
i'm aware that it doesnt use xbind() and other busybox replacement funcs. getting it into a more busybox-ish shape is something i leave as a task for someone more familiar with the busybox internals.

note that i didn't test if the added getsockopt calls are strictly needed, i added them because they were in the original iputils patch.

in general the following differences exist between SOCK_RAW and SOCK_DGRAM handling:

1) the received packet is a raw icmp packet, not an IP one, so it lacks the header and is shorter.
2) the ident (myid) of the packet is sin(6)_port of the sockaddr struct
after doing a bind() and getsockname() on the dgram socket.

the patch works for both "fancy" ping(6), and "non-fancy" ping(6) (the latter just sends one packet and displays whether it was successful or not, without further info).

note that the iputils patch is not upstream yet, so if busybox merges it, it's the first official ping implementation that supports SOCK_DGRAM.

--JS

John Spencer wrote:
Denys Vlasenko wrote:
Applied, thanks.

i just tested this new functionality, and it hangs at recv and does nothing until the alarm is triggered:

 c = recv(pingsock, G.packet, sizeof(G.packet), 0);

(note: in order to test one has to echo groupid groupid > /proc/sys/net/ipv4/ping_group_range as described in the kernel commit:

https://lkml.org/lkml/2011/5/13/382 )

OTOH using the iputils source tarball provided on the kernel patch authors ping info page ( http://openwall.info/wiki/people/segoon/ping ) + the patch there, the resulting ping binary successfully is able to ping as an ordinary user without special privileges, as long as the groupid matches the range) i fixed a couple compile errors in that version of iputils and squashed the needed ping code from that tarball into a single standalone 2KLOC C file - see attachment.


On Tue, Nov 26, 2013 at 10:18 PM, Daniel Borca <[email protected]> wrote:
Allow non-setuid ping.

Reference:
http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c319b4d76b9e583a5d88d6bf190e079c4e43213d

-dborca
--- a/networking/ping.c
+++ b/networking/ping.c
@@ -469,6 +1053,7 @@
        pingsock = 0,
 };
 
+static int using_dgram;
 static void
 #if ENABLE_PING6
 create_icmp_socket(len_and_sockaddr *lsa)
@@ -501,6 +1086,7 @@
                if (sock < 0)
 #endif
                bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
+               using_dgram = 1;
        }
 
        xmove_fd(sock, pingsock);
@@ -551,10 +1137,12 @@
                                bb_perror_msg("recvfrom");
                        continue;
                }
-               if (c >= 76) {                  /* ip + icmp */
-                       struct iphdr *iphdr = (struct iphdr *) G.packet;
+               if (c >= 76 || using_dgram && (c == 64)) {                      
/* ip + icmp */
+                       if(!using_dgram) {
+                               struct iphdr *iphdr = (struct iphdr *) G.packet;
 
-                       pkt = (struct icmp *) (G.packet + (iphdr->ihl << 2));   
/* skip ip hdr */
+                               pkt = (struct icmp *) (G.packet + (iphdr->ihl 
<< 2));   /* skip ip hdr */
+                       } else pkt = (struct icmp *) G.packet;
                        if (pkt->icmp_type == ICMP_ECHOREPLY)
                                break;
                }
@@ -946,19 +1533,21 @@
 }
 static void unpack4(char *buf, int sz, struct sockaddr_in *from)
 {
-       struct icmp *icmppkt;
        struct iphdr *iphdr;
+       struct icmp *icmppkt;
        int hlen;
 
        /* discard if too short */
        if (sz < (datalen + ICMP_MINLEN))
                return;
+       if(!using_dgram) {
+               /* check IP header */
+               iphdr = (struct iphdr *) buf;
+               hlen = iphdr->ihl << 2;
+               sz -= hlen;
+               icmppkt = (struct icmp *) (buf + hlen);
+       } else icmppkt = (struct icmp *) buf;
 
-       /* check IP header */
-       iphdr = (struct iphdr *) buf;
-       hlen = iphdr->ihl << 2;
-       sz -= hlen;
-       icmppkt = (struct icmp *) (buf + hlen);
        if (icmppkt->icmp_id != myid)
                return;                         /* not our ping */
 
@@ -970,7 +1559,7 @@
                        tp = (uint32_t *) icmppkt->icmp_data;
                unpack_tail(sz, tp,
                        inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr),
-                       recv_seq, iphdr->ttl);
+                       recv_seq, using_dgram ? 42 : iphdr->ttl);
        } else if (icmppkt->icmp_type != ICMP_ECHO) {
                bb_error_msg("warning: got ICMP %d (%s)",
                                icmppkt->icmp_type,
@@ -1014,11 +1603,31 @@
        int sockopt;
 
        pingaddr.sin = lsa->u.sin;
-       if (source_lsa) {
+       if (source_lsa && !using_dgram) {
                if (setsockopt(pingsock, IPPROTO_IP, IP_MULTICAST_IF,
                                &source_lsa->u.sa, source_lsa->len))
                        bb_error_msg_and_die("can't set multicast source 
interface");
                xbind(pingsock, &source_lsa->u.sa, source_lsa->len);
+       } else if(using_dgram) {
+               struct sockaddr_in sa;
+               socklen_t sl;
+
+               sa.sin_family = AF_INET;
+               sa.sin_port = 0;
+               sa.sin_addr.s_addr = source_lsa ?
+                       source_lsa->u.sin.sin_addr.s_addr : 0;
+               sl = sizeof(sa);
+
+               if (bind(pingsock, (struct sockaddr *) &sa, sl) == -1) {
+                       perror("bind");
+                       exit(2);
+               }
+
+               if (getsockname(pingsock, (struct sockaddr *) &sa, &sl) == -1) {
+                       perror("getsockname");
+                       exit(2);
+               }
+               myid = sa.sin_port;
        }
 
        /* enable broadcast pings */
@@ -1035,6 +1644,15 @@
                setsockopt(pingsock, IPPROTO_IP, IP_MULTICAST_TTL, &opt_ttl, 
sizeof(opt_ttl));
        }
 
+       if(using_dgram) {
+               int hold = 65536;
+               if (setsockopt(pingsock, SOL_IP, IP_RECVTTL, (char *)&hold, 
sizeof(hold)))
+                       perror("WARNING: setsockopt(IP_RECVTTL)");
+               if (setsockopt(pingsock, SOL_IP, IP_RETOPTS, (char *)&hold, 
sizeof(hold)))
+                       perror("WARNING: setsockopt(IP_RETOPTS)");
+
+       }
+
        signal(SIGINT, print_stats_and_exit);
 
        /* start the ping's going ... */
@@ -1069,10 +1687,33 @@
        char control_buf[CMSG_SPACE(36)];
 
        pingaddr.sin6 = lsa->u.sin6;
-       if (source_lsa)
+       if (source_lsa && !using_dgram)
                xbind(pingsock, &source_lsa->u.sa, source_lsa->len);
+       else if(using_dgram) {
+                struct sockaddr_in6 sa = {0};
+                socklen_t sl;
 
+                sa.sin6_family = AF_INET6;
+                sa.sin6_port = 0;
+               if(source_lsa) {
+                       memcpy(&sa.sin6_addr, &source_lsa->u.sin6.sin6_addr, 
sizeof(struct in6_addr));
+               }
+                sl = sizeof(sa);
+
+                if (bind(pingsock, (struct sockaddr *) &sa, sl) == -1) {
+                        perror("bind");
+                        exit(2);
+                }
+
+                if (getsockname(pingsock, (struct sockaddr *) &sa, &sl) == -1) 
{
+                        perror("getsockname");
+                        exit(2);
+                }
+                myid = sa.sin6_port;
+       }
+
 #ifdef ICMP6_FILTER
+       if(!using_dgram)
        {
                struct icmp6_filter filt;
                if (!(option_mask32 & OPT_VERBOSE)) {
@@ -1198,7 +1839,7 @@
                        str_I = NULL; /* don't try to bind to device later */
                }
        }
-       myid = (uint16_t) getpid();
+       if(!using_dgram) myid = (uint16_t) getpid();
        hostname = argv[optind];
 #if ENABLE_PING6
        {
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to