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