Merge "Support the ping socket in ping6."
diff --git a/ping6.c b/ping6.c
index 019d9e4..2f8dddc 100644
--- a/ping6.c
+++ b/ping6.c
@@ -700,7 +700,7 @@
struct addrinfo hints, *ai;
int gai;
struct sockaddr_in6 firsthop;
- int socket_errno;
+ int socket_errno = 0;
struct icmp6_filter filter;
int err;
#ifdef __linux__
@@ -708,18 +708,24 @@
#endif
static uint32_t scope_id = 0;
+#ifdef ANDROID
+ android_check_security();
+#endif
+
limit_capabilities();
#ifdef USE_IDN
setlocale(LC_ALL, "");
#endif
- enable_capability_raw();
-
- icmp_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
- socket_errno = errno;
-
- disable_capability_raw();
+ icmp_sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
+ if (icmp_sock < 0) {
+ enable_capability_raw();
+ icmp_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+ socket_errno = errno;
+ disable_capability_raw();
+ using_ping_socket = 0;
+ }
source.sin6_family = AF_INET6;
memset(&firsthop, 0, sizeof(firsthop));
@@ -787,6 +793,10 @@
printf("ping6 utility, iputils-%s\n", SNAPSHOT);
exit(0);
case 'N':
+ if (using_ping_socket) {
+ fprintf(stderr, "ping: -N requires raw socket permissions\n");
+ exit(2);
+ }
if (niquery_option_handler(optarg) < 0) {
usage();
break;
@@ -1092,49 +1102,53 @@
hold += ((hold+511)/512)*(40+16+64+160);
sock_setbufs(icmp_sock, hold);
+ if (!using_ping_socket) {
#ifdef __linux__
- csum_offset = 2;
- sz_opt = sizeof(int);
+ csum_offset = 2;
+ sz_opt = sizeof(int);
- err = setsockopt(icmp_sock, SOL_RAW, IPV6_CHECKSUM, &csum_offset, sz_opt);
- if (err < 0) {
- /* checksum should be enabled by default and setting this
- * option might fail anyway.
- */
- fprintf(stderr, "setsockopt(RAW_CHECKSUM) failed - try to continue.");
- }
+ err = setsockopt(icmp_sock, SOL_RAW, IPV6_CHECKSUM,
+ &csum_offset, sz_opt);
+ if (err < 0) {
+ /* checksum should be enabled by default and setting
+ * this option might fail anyway.
+ */
+ fprintf(stderr, "setsockopt(RAW_CHECKSUM) failed"
+ " - try to continue.");
+ }
#endif
- /*
- * select icmp echo reply as icmp type to receive
- */
+ /*
+ * select icmp echo reply as icmp type to receive
+ */
- ICMP6_FILTER_SETBLOCKALL(&filter);
+ ICMP6_FILTER_SETBLOCKALL(&filter);
- if (!working_recverr) {
- ICMP6_FILTER_SETPASS(ICMP6_DST_UNREACH, &filter);
- ICMP6_FILTER_SETPASS(ICMP6_PACKET_TOO_BIG, &filter);
- ICMP6_FILTER_SETPASS(ICMP6_TIME_EXCEEDED, &filter);
- ICMP6_FILTER_SETPASS(ICMP6_PARAM_PROB, &filter);
- }
+ if (!working_recverr) {
+ ICMP6_FILTER_SETPASS(ICMP6_DST_UNREACH, &filter);
+ ICMP6_FILTER_SETPASS(ICMP6_PACKET_TOO_BIG, &filter);
+ ICMP6_FILTER_SETPASS(ICMP6_TIME_EXCEEDED, &filter);
+ ICMP6_FILTER_SETPASS(ICMP6_PARAM_PROB, &filter);
+ }
- if (niquery_is_enabled())
- ICMP6_FILTER_SETPASS(ICMPV6_NI_REPLY, &filter);
- else
- ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
+ if (niquery_is_enabled())
+ ICMP6_FILTER_SETPASS(ICMPV6_NI_REPLY, &filter);
+ else
+ ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
- err = setsockopt(icmp_sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
- sizeof(struct icmp6_filter));
+ err = setsockopt(icmp_sock, IPPROTO_ICMPV6, ICMP6_FILTER,
+ &filter, sizeof(struct icmp6_filter));
- if (err < 0) {
- perror("setsockopt(ICMP6_FILTER)");
- exit(2);
+ if (err < 0) {
+ perror("setsockopt(ICMP6_FILTER)");
+ exit(2);
+ }
}
if (options & F_NOLOOP) {
int loop = 0;
if (setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
- &loop, sizeof(loop)) == -1) {
+ &loop, sizeof(loop)) == -1) {
perror ("can't disable multicast loopback");
exit(2);
}