pmaports/busybox/0004-ping-make-ping-work-without-root-privileges.patch
Oliver Smith 1c0ff6aa23 Put postmarketOS aports inside pmbootstrap repo
Later, the aports folder will probably get split up in its own repository.
But right now this is simply convenient.
2017-05-26 22:26:25 +02:00

197 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