0016-ping-make-ping-work-without-root-privileges.patch (6389B)
1 From 19c6c34fb6318605e58a9b209cf742d559c0d467 Mon Sep 17 00:00:00 2001 2 From: Natanael Copa <ncopa@alpinelinux.org> 3 Date: Tue, 29 Mar 2016 09:23:08 +0200 4 Subject: [PATCH] ping: make ping work without root privileges 5 MIME-Version: 1.0 6 Content-Type: text/plain; charset=UTF-8 7 Content-Transfer-Encoding: 8bit 8 9 --- 10 networking/ping.c | 115 +++++++++++++++++++++++++++++++++++++--------- 11 1 file changed, 94 insertions(+), 21 deletions(-) 12 13 diff --git a/networking/ping.c b/networking/ping.c 14 index 9805695a1..5e4488abd 100644 15 --- a/networking/ping.c 16 +++ b/networking/ping.c 17 @@ -208,6 +208,7 @@ enum { 18 pingsock = 0, 19 }; 20 21 +static int using_dgram; 22 static void 23 #if ENABLE_PING6 24 create_icmp_socket(len_and_sockaddr *lsa) 25 @@ -224,9 +225,23 @@ create_icmp_socket(void) 26 #endif 27 sock = socket(AF_INET, SOCK_RAW, 1); /* 1 == ICMP */ 28 if (sock < 0) { 29 - if (errno == EPERM) 30 - bb_simple_error_msg_and_die(bb_msg_perm_denied_are_you_root); 31 - bb_simple_perror_msg_and_die(bb_msg_can_not_create_raw_socket); 32 + if (errno != EPERM) 33 + bb_simple_perror_msg_and_die(bb_msg_can_not_create_raw_socket); 34 +#if defined(__linux__) || defined(__APPLE__) 35 + /* We don't have root privileges. Try SOCK_DGRAM instead. 36 + * Linux needs net.ipv4.ping_group_range for this to work. 37 + * MacOSX allows ICMP_ECHO, ICMP_TSTAMP or ICMP_MASKREQ 38 + */ 39 +#if ENABLE_PING6 40 + if (lsa->u.sa.sa_family == AF_INET6) 41 + sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6); 42 + else 43 +#endif 44 + sock = socket(AF_INET, SOCK_DGRAM, 1); /* 1 == ICMP */ 45 + if (sock < 0) 46 +#endif 47 + bb_simple_error_msg_and_die(bb_msg_perm_denied_are_you_root); 48 + using_dgram = 1; 49 } 50 51 xmove_fd(sock, pingsock); 52 @@ -279,10 +294,12 @@ static void ping4(len_and_sockaddr *lsa) 53 bb_simple_perror_msg("recvfrom"); 54 continue; 55 } 56 - if (c >= 76) { /* ip + icmp */ 57 - struct iphdr *iphdr = (struct iphdr *) G.packet; 58 + if (c >= 76 || using_dgram && (c == 64)) { /* ip + icmp */ 59 + if(!using_dgram) { 60 + struct iphdr *iphdr = (struct iphdr *) G.packet; 61 62 - pkt = (struct icmp *) (G.packet + (iphdr->ihl << 2)); /* skip ip hdr */ 63 + pkt = (struct icmp *) (G.packet + (iphdr->ihl << 2)); /* skip ip hdr */ 64 + } else pkt = (struct icmp *) G.packet; 65 if (pkt->icmp_id != G.myid) 66 continue; /* not our ping */ 67 if (pkt->icmp_type == ICMP_ECHOREPLY) 68 @@ -691,19 +708,21 @@ static void unpack_tail(int sz, uint32_t *tp, 69 } 70 static int unpack4(char *buf, int sz, struct sockaddr_in *from) 71 { 72 - struct icmp *icmppkt; 73 struct iphdr *iphdr; 74 + struct icmp *icmppkt; 75 int hlen; 76 77 /* discard if too short */ 78 if (sz < (datalen + ICMP_MINLEN)) 79 return 0; 80 + if(!using_dgram) { 81 + /* check IP header */ 82 + iphdr = (struct iphdr *) buf; 83 + hlen = iphdr->ihl << 2; 84 + sz -= hlen; 85 + icmppkt = (struct icmp *) (buf + hlen); 86 + } else icmppkt = (struct icmp *) buf; 87 88 - /* check IP header */ 89 - iphdr = (struct iphdr *) buf; 90 - hlen = iphdr->ihl << 2; 91 - sz -= hlen; 92 - icmppkt = (struct icmp *) (buf + hlen); 93 if (icmppkt->icmp_id != myid) 94 return 0; /* not our ping */ 95 96 @@ -715,7 +734,7 @@ static int unpack4(char *buf, int sz, struct sockaddr_in *from) 97 tp = (uint32_t *) icmppkt->icmp_data; 98 unpack_tail(sz, tp, 99 inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr), 100 - recv_seq, iphdr->ttl); 101 + recv_seq, using_dgram ? 42 : iphdr->ttl); 102 return 1; 103 } 104 if (icmppkt->icmp_type != ICMP_ECHO) { 105 @@ -765,11 +784,31 @@ static void ping4(len_and_sockaddr *lsa) 106 int sockopt; 107 108 pingaddr.sin = lsa->u.sin; 109 - if (source_lsa) { 110 + if (source_lsa && !using_dgram) { 111 if (setsockopt(pingsock, IPPROTO_IP, IP_MULTICAST_IF, 112 &source_lsa->u.sa, source_lsa->len)) 113 bb_simple_error_msg_and_die("can't set multicast source interface"); 114 xbind(pingsock, &source_lsa->u.sa, source_lsa->len); 115 + } else if(using_dgram) { 116 + struct sockaddr_in sa; 117 + socklen_t sl; 118 + 119 + sa.sin_family = AF_INET; 120 + sa.sin_port = 0; 121 + sa.sin_addr.s_addr = source_lsa ? 122 + source_lsa->u.sin.sin_addr.s_addr : 0; 123 + sl = sizeof(sa); 124 + 125 + if (bind(pingsock, (struct sockaddr *) &sa, sl) == -1) { 126 + perror("bind"); 127 + exit(2); 128 + } 129 + 130 + if (getsockname(pingsock, (struct sockaddr *) &sa, &sl) == -1) { 131 + perror("getsockname"); 132 + exit(2); 133 + } 134 + myid = sa.sin_port; 135 } 136 137 /* enable broadcast pings */ 138 @@ -786,6 +825,15 @@ static void ping4(len_and_sockaddr *lsa) 139 setsockopt_int(pingsock, IPPROTO_IP, IP_MULTICAST_TTL, opt_ttl); 140 } 141 142 + if(using_dgram) { 143 + int hold = 65536; 144 + if (setsockopt(pingsock, SOL_IP, IP_RECVTTL, (char *)&hold, sizeof(hold))) 145 + perror("WARNING: setsockopt(IP_RECVTTL)"); 146 + if (setsockopt(pingsock, SOL_IP, IP_RETOPTS, (char *)&hold, sizeof(hold))) 147 + perror("WARNING: setsockopt(IP_RETOPTS)"); 148 + 149 + } 150 + 151 signal(SIGINT, print_stats_and_exit); 152 153 /* start the ping's going ... */ 154 @@ -823,10 +871,33 @@ static void ping6(len_and_sockaddr *lsa) 155 char control_buf[CMSG_SPACE(36)]; 156 157 pingaddr.sin6 = lsa->u.sin6; 158 - if (source_lsa) 159 + if (source_lsa && !using_dgram) 160 xbind(pingsock, &source_lsa->u.sa, source_lsa->len); 161 + else if(using_dgram) { 162 + struct sockaddr_in6 sa = {0}; 163 + socklen_t sl; 164 + 165 + sa.sin6_family = AF_INET6; 166 + sa.sin6_port = 0; 167 + if(source_lsa) { 168 + memcpy(&sa.sin6_addr, &source_lsa->u.sin6.sin6_addr, sizeof(struct in6_addr)); 169 + } 170 + sl = sizeof(sa); 171 + 172 + if (bind(pingsock, (struct sockaddr *) &sa, sl) == -1) { 173 + perror("bind"); 174 + exit(2); 175 + } 176 + 177 + if (getsockname(pingsock, (struct sockaddr *) &sa, &sl) == -1) { 178 + perror("getsockname"); 179 + exit(2); 180 + } 181 + myid = sa.sin6_port; 182 + } 183 184 #ifdef ICMP6_FILTER 185 + if(!using_dgram) 186 { 187 struct icmp6_filter filt; 188 if (!(option_mask32 & OPT_VERBOSE)) { 189 @@ -972,12 +1043,14 @@ static int common_ping_main(int opt, char **argv) 190 interval = INT_MAX/1000000; 191 G.interval_us = interval * 1000000; 192 193 - myid = (uint16_t) getpid(); 194 - /* we can use native-endian ident, but other Unix ping/traceroute 195 - * utils use *big-endian pid*, and e.g. traceroute on our machine may be 196 - * *not* from busybox, idents may collide. Follow the convention: 197 - */ 198 - myid = htons(myid); 199 + if (!using_dgram) { 200 + myid = (uint16_t) getpid(); 201 + /* we can use native-endian ident, but other Unix ping/traceroute 202 + * utils use *big-endian pid*, and e.g. traceroute on our machine may be 203 + * *not* from busybox, idents may collide. Follow the convention: 204 + */ 205 + myid = htons(myid); 206 + } 207 hostname = argv[optind]; 208 #if ENABLE_PING6 209 {