210 lines
6.2 KiB
Diff
210 lines
6.2 KiB
Diff
From c682e9410adfdfeb33d507fe0daeda581a07becf Mon Sep 17 00:00:00 2001
|
|
From: Natanael Copa <ncopa@alpinelinux.org>
|
|
Date: Tue, 29 Mar 2016 09:23:08 +0200
|
|
Subject: [PATCH] ping: make ping work without root privileges
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
---
|
|
networking/ping.c | 115 +++++++++++++++++++++++++++++++++++++---------
|
|
1 file changed, 94 insertions(+), 21 deletions(-)
|
|
|
|
diff --git a/networking/ping.c b/networking/ping.c
|
|
index b7e6955a9..dab5101c7 100644
|
|
--- a/networking/ping.c
|
|
+++ b/networking/ping.c
|
|
@@ -208,6 +208,7 @@ enum {
|
|
pingsock = 0,
|
|
};
|
|
|
|
+static int using_dgram;
|
|
static void
|
|
#if ENABLE_PING6
|
|
create_icmp_socket(len_and_sockaddr *lsa)
|
|
@@ -224,9 +225,23 @@ create_icmp_socket(void)
|
|
#endif
|
|
sock = socket(AF_INET, SOCK_RAW, 1); /* 1 == ICMP */
|
|
if (sock < 0) {
|
|
- if (errno == EPERM)
|
|
- bb_simple_error_msg_and_die(bb_msg_perm_denied_are_you_root);
|
|
- bb_simple_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
|
|
+ if (errno != EPERM)
|
|
+ bb_simple_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
|
|
+#if defined(__linux__) || defined(__APPLE__)
|
|
+ /* We don't have root privileges. Try SOCK_DGRAM instead.
|
|
+ * Linux needs net.ipv4.ping_group_range for this to work.
|
|
+ * MacOSX allows ICMP_ECHO, ICMP_TSTAMP or ICMP_MASKREQ
|
|
+ */
|
|
+#if ENABLE_PING6
|
|
+ if (lsa->u.sa.sa_family == AF_INET6)
|
|
+ sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
|
|
+ else
|
|
+#endif
|
|
+ sock = socket(AF_INET, SOCK_DGRAM, 1); /* 1 == ICMP */
|
|
+ if (sock < 0)
|
|
+#endif
|
|
+ bb_simple_error_msg_and_die(bb_msg_perm_denied_are_you_root);
|
|
+ using_dgram = 1;
|
|
}
|
|
|
|
xmove_fd(sock, pingsock);
|
|
@@ -279,10 +294,12 @@ static void ping4(len_and_sockaddr *lsa)
|
|
bb_simple_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_id != G.myid)
|
|
continue; /* not our ping */
|
|
if (pkt->icmp_type == ICMP_ECHOREPLY)
|
|
@@ -691,19 +708,21 @@ static void unpack_tail(int sz, uint32_t *tp,
|
|
}
|
|
static int 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 0;
|
|
+ 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 0; /* not our ping */
|
|
|
|
@@ -715,7 +734,7 @@ static int unpack4(char *buf, int sz, struct sockaddr_in *from)
|
|
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);
|
|
return 1;
|
|
}
|
|
if (icmppkt->icmp_type != ICMP_ECHO) {
|
|
@@ -765,11 +784,31 @@ static void ping4(len_and_sockaddr *lsa)
|
|
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_simple_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 */
|
|
@@ -786,6 +825,15 @@ static void ping4(len_and_sockaddr *lsa)
|
|
setsockopt_int(pingsock, IPPROTO_IP, IP_MULTICAST_TTL, 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 ... */
|
|
@@ -823,10 +871,33 @@ static void ping6(len_and_sockaddr *lsa)
|
|
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)) {
|
|
@@ -972,12 +1043,14 @@ static int common_ping_main(int opt, char **argv)
|
|
interval = INT_MAX/1000000;
|
|
G.interval_us = interval * 1000000;
|
|
|
|
- myid = (uint16_t) getpid();
|
|
- /* we can use native-endian ident, but other Unix ping/traceroute
|
|
- * utils use *big-endian pid*, and e.g. traceroute on our machine may be
|
|
- * *not* from busybox, idents may collide. Follow the convention:
|
|
- */
|
|
- myid = htons(myid);
|
|
+ if (!using_dgram) {
|
|
+ myid = (uint16_t) getpid();
|
|
+ /* we can use native-endian ident, but other Unix ping/traceroute
|
|
+ * utils use *big-endian pid*, and e.g. traceroute on our machine may be
|
|
+ * *not* from busybox, idents may collide. Follow the convention:
|
|
+ */
|
|
+ myid = htons(myid);
|
|
+ }
|
|
hostname = argv[optind];
|
|
#if ENABLE_PING6
|
|
{
|