traceroute: commonalize verbose printing

function                                             old     new   delta
hexdump                                                -     274    +274
traceroute_init                                     1172    1147     -25
pr_type                                               79       -     -79
common_traceroute_main                              2091    1785    -306
------------------------------------------------------------------------------
(add/remove: 1/1 grow/shrink: 0/2 up/down: 274/-410)         Total: -136 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/networking/traceroute.c b/networking/traceroute.c
index cf2b3cc..0fb01ff 100644
--- a/networking/traceroute.c
+++ b/networking/traceroute.c
@@ -358,7 +358,11 @@
 	OPT_IPV4         = (1 << 17),   /* 4 */
 	OPT_IPV6         = (1 << 18) * ENABLE_TRACEROUTE6, /* 6 */
 };
-#define verbose (option_mask32 & OPT_VERBOSE)
+#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
+# define verbose (option_mask32 & OPT_VERBOSE)
+#else
+# define verbose 0
+#endif
 
 enum {
 	SIZEOF_ICMP_HDR = 8,
@@ -559,9 +563,7 @@
 }
 
 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE
-/*
- * Convert an ICMP "type" field to a printable string.
- */
+/* Convert an ICMP "type" field to a printable string */
 static const char *
 pr_type(unsigned char t)
 {
@@ -594,12 +596,35 @@
 
 	return ttab[t];
 }
+static void
+hexdump(const struct icmp *icp, int len)
+{
+	const unsigned char *p;
+	int i;
+
+	printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n",
+		len,
+		auto_string(xmalloc_sockaddr2dotted_noport(&G.from_lsa->u.sa)),
+		auto_string(xmalloc_sockaddr2dotted_noport(G.to)),
+		icp->icmp_type, pr_type(icp->icmp_type),
+		icp->icmp_code
+	);
+	p = (const void *)icp;
+	for (i = 0; i < len; i++) {
+		if (i % 16 == 0)
+			printf("%04x:", i);
+		if (i % 4 == 0)
+			bb_putchar(' ');
+		printf("%02x", p[i]);
+		if ((i % 16 == 15) && (i + 1 < len))
+			bb_putchar('\n');
+	}
+	bb_putchar('\n');
+}
+#else
+# define hexdump(...) ((void)0)
 #endif
 
-#if !ENABLE_FEATURE_TRACEROUTE_VERBOSE
-#define packet4_ok(read_len, from, seq) \
-	packet4_ok(read_len, seq)
-#endif
 static int
 packet4_ok(int read_len, int seq)
 {
@@ -616,11 +641,9 @@
 
 	hlen = ip->ip_hl << 2;
 	if (read_len < hlen + ICMP_MINLEN) {
-#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
 		if (verbose)
 			printf("packet too short (%d bytes) from %s\n", read_len,
 				inet_ntoa(G.from_lsa->u.sin.sin_addr));
-#endif
 		return 0;
 	}
 	read_len -= hlen;
@@ -677,24 +700,8 @@
 			}
 		}
 	}
-#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
-	if (verbose) {
-		int i;
-		uint32_t *lp = (uint32_t *)&icp->icmp_ip;
-
-		printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n",
-			read_len,
-			/* inet_ntoa(G.from_lsa->u.sin.sin_addr) - two calls of inet_ntoa()
-			 * are unsafe (use the same buffer), using this instead:
-			 */
-			auto_string(xmalloc_sockaddr2dotted_noport(&G.from_lsa->u.sa)),
-			inet_ntoa(ip->ip_dst),
-			type, pr_type(type), icp->icmp_code
-		);
-		for (i = 4; i < read_len; i += sizeof(*lp))
-			printf("%2d: x%8.8x\n", i, *lp++);
-	}
-#endif
+	if (verbose)
+		hexdump(icp, read_len);
 	return 0;
 }
 
@@ -754,34 +761,9 @@
 			}
 		}
 	}
-
-# if ENABLE_FEATURE_TRACEROUTE_VERBOSE
-	if (verbose) {
-		unsigned char *p;
-		int i;
-
-		p = (unsigned char *) (icp + 1);
-
-		printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n",
-			read_len,
-			auto_string(xmalloc_sockaddr2dotted_noport(&G.from_lsa->u.sa)),
-			auto_string(xmalloc_sockaddr2dotted_noport(G.to)),
-			type, pr_type(type), icp->icmp6_code
-		);
-		read_len -= sizeof(struct icmp6_hdr);
-		for (i = 0; i < read_len; i++) {
-			if (i % 16 == 0)
-				printf("%04x:", i);
-			if (i % 4 == 0)
-				bb_putchar(' ');
-			printf("%02x", p[i]);
-			if ((i % 16 == 15) && (i + 1 < read_len))
-				bb_putchar('\n');
-		}
-		bb_putchar('\n');
-	}
-# endif
-
+	if (verbose)
+		/* cast is safe since the beginning of icmp4 and icmp6 layouts match */
+		hexdump((const struct icmp *)icp, read_len);
 	return 0;
 }
 
@@ -910,7 +892,7 @@
 		packlen = sizeof(struct ip)
 			+ SIZEOF_ICMP_HDR
 			+ sizeof(struct outdata_t);
-		port = 0; /* on ICMP6 sockets, sendto(ipv6.nonzero_port) throws EINVAL */
+		port = 0; /* on ICMP6 sockets, sendto(ipv6.nonzero_port) throws EINVAL! */
 	}
 #if ENABLE_TRACEROUTE6
 	af = AF_UNSPEC;
@@ -932,23 +914,24 @@
 #else
 	dest_lsa = xhost2sockaddr(argv[0], port);
 #endif
+//TODO: make sure af == AF_INET[6]? (FEATURE_UNIX_LOCAL=y allows "local:/PATH" to be translated to AF_UNIX)
 	G.from_lsa = xmemdup(dest_lsa, LSA_LEN_SIZE + dest_lsa->len);
 	G.to = xzalloc(dest_lsa->len);
 	if (argv[1])
 		packlen = xatoul_range(argv[1], packlen, 32 * 1024);
 
-#if ENABLE_TRACEROUTE6
-	if (af == AF_INET6) {
-		xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), rcvsock);
-		/* want recvmsg to report target local address (for -v) */
-		setsockopt_1(rcvsock, SOL_IPV6, IPV6_RECVPKTINFO);
-	} else
-#endif
-	{
+	if (af == AF_INET) {
 		xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock);
 		/* want recvmsg to report target local address (for -v) */
 		setsockopt_1(rcvsock, IPPROTO_IP, IP_PKTINFO);
 	}
+#if ENABLE_TRACEROUTE6
+	else {
+		xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), rcvsock);
+		/* want recvmsg to report target local address (for -v) */
+		setsockopt_1(rcvsock, SOL_IPV6, IPV6_RECVPKTINFO);
+	}
+#endif
 
 #if TRACEROUTE_SO_DEBUG
 	if (op & OPT_DEBUG)
@@ -959,22 +942,22 @@
 
 	{
 		int snd;
+		if (af == AF_INET) {
+			if (op & OPT_USE_ICMP)
+				snd = xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+			else
+				snd = xsocket(AF_INET, SOCK_DGRAM, 0);
+		}
 #if ENABLE_TRACEROUTE6
-		if (af == AF_INET6) {
+		else {
 			if (setsockopt_int(rcvsock, SOL_RAW, IPV6_CHECKSUM, 2) != 0)
 				bb_perror_msg_and_die("setsockopt(%s)", "IPV6_CHECKSUM");
 			if (op & OPT_USE_ICMP)
 				snd = xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
 			else
 				snd = xsocket(AF_INET6, SOCK_DGRAM, 0);
-		} else
-#endif
-		{
-			if (op & OPT_USE_ICMP)
-				snd = xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
-			else
-				snd = xsocket(AF_INET, SOCK_DGRAM, 0);
 		}
+#endif
 		xmove_fd(snd, sndsock);
 	}
 
@@ -1006,7 +989,7 @@
 	ident = getpid();
 
 	outdata = (void*)(outudp + 1);
-	if (!ENABLE_TRACEROUTE6 || af == AF_INET) {
+	if (af == AF_INET) {
 		if (op & OPT_USE_ICMP) {
 			outicmp->icmp_type = ICMP_ECHO;
 			/*outicmp->icmp_code = 0; - set by xzalloc */
@@ -1015,7 +998,7 @@
 		}
 	}
 #if ENABLE_TRACEROUTE6
-	if (af == AF_INET6) {
+	else {
 		outdata = (void*)(outudp6 + 1);
 		if (op & OPT_USE_ICMP) {
 			outicmp6->icmp_type = ICMP6_ECHO_REQUEST;
@@ -1048,26 +1031,22 @@
 		xbind(sndsock, &source_lsa->u.sa, source_lsa->len);
 		if (ENABLE_FEATURE_CLEAN_UP)
 			free(source_lsa);
-	}
-#if ENABLE_TRACEROUTE6
-	else if (af == AF_INET6) {
-//TODO: why we don't do it for IPv4?
+	} else {
 		len_and_sockaddr *source_lsa;
 
 		set_nport(&dest_lsa->u.sa, htons(port));
-		/* Connect makes kernel pick source IP and port */
+		/* Connect makes kernel pick source IP (and port if UDP) */
 		xconnect(sndsock, &dest_lsa->u.sa, dest_lsa->len);
 		/* Read IP and port */
 		source_lsa = get_sock_lsa(sndsock);
 		if (source_lsa == NULL)
-			bb_simple_error_msg_and_die("can't get probe addr");
-		/* bind our recv socket to this IP (but not port) */
-		set_nport(&source_lsa->u.sa, 0);
+			bb_simple_perror_msg_and_die("getsockname");
+		/* bind our recv ICMP socket to this IP (but not port, ICMP has no ports) */
+		//set_nport(&source_lsa->u.sa, 0); - paranoia, seems to work without this for both ipv4 and ipv6
 		xbind(rcvsock, &source_lsa->u.sa, source_lsa->len);
 		if (ENABLE_FEATURE_CLEAN_UP)
 			free(source_lsa);
 	}
-#endif
 
 	/* Revert to non-privileged user after opening sockets */
 	xsetgid(getgid());