Support the ping socket in ping6.

Bug: 9469682
Change-Id: I1043ffef9b4a353546871b0c80de7fdecf2d5765
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);
 		}