198 lines
5.9 KiB
Diff
198 lines
5.9 KiB
Diff
|
From 9432235d7dc8d4a2bc9b546e63e52e84b7cad5ce Mon Sep 17 00:00:00 2001
|
||
|
From: Natanael Copa <ncopa@alpinelinux.org>
|
||
|
Date: Tue, 29 Mar 2016 18:59:22 +0200
|
||
|
Subject: [PATCH 04/12] ping: make ping work without root privileges
|
||
|
|
||
|
---
|
||
|
networking/ping.c | 103 +++++++++++++++++++++++++++++++++++++++++++++---------
|
||
|
1 file changed, 87 insertions(+), 16 deletions(-)
|
||
|
|
||
|
diff --git a/networking/ping.c b/networking/ping.c
|
||
|
index d0ef7ba62..73e903927 100644
|
||
|
--- a/networking/ping.c
|
||
|
+++ b/networking/ping.c
|
||
|
@@ -155,6 +155,7 @@ enum {
|
||
|
pingsock = 0,
|
||
|
};
|
||
|
|
||
|
+static int using_dgram;
|
||
|
static void
|
||
|
#if ENABLE_PING6
|
||
|
create_icmp_socket(len_and_sockaddr *lsa)
|
||
|
@@ -171,9 +172,23 @@ create_icmp_socket(void)
|
||
|
#endif
|
||
|
sock = socket(AF_INET, SOCK_RAW, 1); /* 1 == ICMP */
|
||
|
if (sock < 0) {
|
||
|
- if (errno == EPERM)
|
||
|
- bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
|
||
|
- bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
|
||
|
+ if (errno != EPERM)
|
||
|
+ bb_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_error_msg_and_die(bb_msg_perm_denied_are_you_root);
|
||
|
+ using_dgram = 1;
|
||
|
}
|
||
|
|
||
|
xmove_fd(sock, pingsock);
|
||
|
@@ -226,10 +241,12 @@ static void ping4(len_and_sockaddr *lsa)
|
||
|
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_id != G.myid)
|
||
|
continue; /* not our ping */
|
||
|
if (pkt->icmp_type == ICMP_ECHOREPLY)
|
||
|
@@ -627,19 +644,21 @@ static void unpack_tail(int sz, uint32_t *tp,
|
||
|
}
|
||
|
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 */
|
||
|
|
||
|
@@ -651,7 +670,7 @@ static void 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);
|
||
|
} else if (icmppkt->icmp_type != ICMP_ECHO) {
|
||
|
bb_error_msg("warning: got ICMP %d (%s)",
|
||
|
icmppkt->icmp_type,
|
||
|
@@ -695,11 +714,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_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 */
|
||
|
@@ -716,6 +755,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 ... */
|
||
|
@@ -749,10 +797,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)) {
|
||
|
@@ -880,7 +951,7 @@ static int common_ping_main(int opt, char **argv)
|
||
|
if (opt & OPT_p)
|
||
|
G.pattern = xstrtou_range(str_p, 16, 0, 255);
|
||
|
|
||
|
- myid = (uint16_t) getpid();
|
||
|
+ if (!using_dgram) myid = (uint16_t) getpid();
|
||
|
hostname = argv[optind];
|
||
|
#if ENABLE_PING6
|
||
|
{
|
||
|
--
|
||
|
2.11.0
|
||
|
|