From eugen@eg.sd.rdtc.ru  Thu Mar 13 10:54:51 2014
Return-Path: <eugen@eg.sd.rdtc.ru>
Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115])
	(using TLSv1 with cipher ADH-AES256-SHA (256/256 bits))
	(No client certificate requested)
	by hub.freebsd.org (Postfix) with ESMTPS id 3A492DA4
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 13 Mar 2014 10:54:51 +0000 (UTC)
Received: from hz.grosbein.net (hz.grosbein.net [78.47.246.247])
	(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
	(No client certificate requested)
	by mx1.freebsd.org (Postfix) with ESMTPS id 701E37FE
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 13 Mar 2014 10:54:48 +0000 (UTC)
Received: from eg.sd.rdtc.ru (root@eg.sd.rdtc.ru [62.231.161.221])
	by hz.grosbein.net (8.14.7/8.14.7) with ESMTP id s2DAsXTZ052980
	(version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NOT)
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 13 Mar 2014 11:54:34 +0100 (CET)
	(envelope-from eugen@eg.sd.rdtc.ru)
Received: from eg.sd.rdtc.ru (eugen@localhost [127.0.0.1])
	by eg.sd.rdtc.ru (8.14.7/8.14.7) with ESMTP id s2DAsOb7062556
	(version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT);
	Thu, 13 Mar 2014 17:54:24 +0700 (NOVT)
	(envelope-from eugen@eg.sd.rdtc.ru)
Received: (from eugen@localhost)
	by eg.sd.rdtc.ru (8.14.7/8.14.7/Submit) id s2DAsOsa062555;
	Thu, 13 Mar 2014 17:54:24 +0700 (NOVT)
	(envelope-from eugen)
Message-Id: <201403131054.s2DAsOsa062555@eg.sd.rdtc.ru>
Date: Thu, 13 Mar 2014 17:54:24 +0700 (NOVT)
From: Eugene Grosbein <eugen@grosbein.net>
To: FreeBSD-gnats-submit@freebsd.org
Subject: [patch] traceroute -a breaks of "whois" socket timeout
X-Send-Pr-Version: 3.114
X-GNATS-Notify:

>Number:         187526
>Category:       bin
>Synopsis:       [patch] traceroute(8): traceroute -a breaks of "whois" socket timeout
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Mar 13 11:00:00 UTC 2014
>Closed-Date:    
>Last-Modified:  Wed Apr 16 01:51:07 UTC 2014
>Originator:     Eugene Grosbein
>Release:        FreeBSD 8.4-STABLE amd64
>Organization:
RDTC JSC
>Environment:
System: FreeBSD eg.sd.rdtc.ru 8.4-STABLE FreeBSD 8.4-STABLE #3 r251830M: Mon Sep 30 18:01:03 NOVT 2013 root@eg.sd.rdtc.ru:/usr/local/obj/usr/local/src/sys/EG amd64

>Description:
	"traceroute -a" opens TCP socket to whois server and fails to check
	if this socket stays valid during (sometimes long) runtime.
	If whois server closes this connection, traceroute gets EOF at next
	hop (and shows AS0) and is killed with SIGPIPE later.

>How-To-Repeat:

$ traceroute -Ia 194.150.149.239
traceroute to 194.150.149.239 (194.150.149.239), 64 hops max, 72 byte packets
 1  [AS29072] 62.231.161.217 (62.231.161.217)  0.276 ms  0.268 ms  0.189 ms
 2  [AS29072] k-45.rdtc.ru (62.231.160.42)  1.169 ms  0.496 ms  0.706 ms
 3  [AS29072] asbr.rdtc.ru (62.231.191.137)  0.467 ms  0.548 ms  0.498 ms
 4  [AS31133] 37.29.3.49 (37.29.3.49)  1.423 ms  1.650 ms  1.374 ms
 5  * * *
 6  * * *
 7  * * *
 8  * * *
 9  * * *
10  * * *
11  [AS0] 37.29.107.202 (37.29.107.202)  70.641 ms  70.599 ms  70.525 ms

	Here traceroute is killed. Instead, it should show complete trace:

11  [AS31133] 37.29.107.202 (37.29.107.202)  104.550 ms  70.603 ms  72.888 ms
12  [AS12389] 95.167.91.93 (95.167.91.93)  166.594 ms  65.702 ms  65.790 ms
13  [AS12389] customer-as41440.xe-0-2-0.brnl-rgr3.sib.ip.rostelecom.ru (188.254.36.146)  68.412 ms  68.322 ms  68.287 ms
14  [AS41440] ge-0-0-0-v501.bar-csr1.ncc.sibirtelecom.ru (213.228.118.6)  85.369 ms  101.501 ms  85.300 ms
15  [AS12846] 212.94.98.54 (212.94.98.54)  85.021 ms  85.116 ms  85.004 ms
16  [AS12846] Bsk-ATS24-c7301.mss.ab.ru (212.94.101.129)  74.240 ms  74.504 ms  74.214 ms
17  [AS12846] adsl-149-239.biysk.ru (194.150.149.239)  103.236 ms  103.358 ms  103.013 ms

>Fix:

	A workaround is to lower wait time for proble timeout using '-w 1' option.

	The following patch fixes the problem introducing proper error checking
	while reading/writing "whois" connection. In case of error it reconnects.

--- as.h.orig	2013-06-17 11:18:23.000000000 +0700
+++ as.h	2014-03-13 17:13:48.000000000 +0700
@@ -31,5 +31,5 @@
  */
 
 void *as_setup(const char *);
-unsigned int as_lookup(void *, char *, sa_family_t);
+unsigned int as_lookup(void *, char *, sa_family_t, int *);
 void as_shutdown(void *);
--- as.c.orig	2013-06-17 11:18:23.000000000 +0700
+++ as.c	2014-03-13 17:37:51.000000000 +0700
@@ -119,7 +119,7 @@ as_setup(const char *server)
 }
 
 unsigned int
-as_lookup(void *_asn, char *addr, sa_family_t family)
+as_lookup(void *_asn, char *addr, sa_family_t family, int *status)
 {
 	struct aslookup *asn = _asn;
 	char buf[1024];
@@ -129,8 +129,17 @@ as_lookup(void *_asn, char *addr, sa_fam
 	as = 0;
 	rc = dlen = 0;
 	plen = (family == AF_INET6) ? 128 : 32;
-	(void)fprintf(asn->as_f, "!r%s/%d,l\n", addr, plen);
-	(void)fflush(asn->as_f);
+	*status = fprintf(asn->as_f, "!r%s/%d,l\n", addr, plen);
+	if (*status < 0) {
+		*status = errno;
+		return 0;
+	}
+	*status = fflush(asn->as_f);
+	if (*status == EOF) {
+		*status = errno;
+		return 0;
+	}
+	*status = 0;
 
 #ifdef AS_DEBUG_FILE
 	if (asn->as_debug) {
@@ -139,7 +148,14 @@ as_lookup(void *_asn, char *addr, sa_fam
 	}
 #endif /* AS_DEBUG_FILE */
 
-	while (fgets(buf, sizeof(buf), asn->as_f) != NULL) {
+	while (1) {
+		if (fgets(buf, sizeof(buf), asn->as_f) == NULL) {
+			if(feof(asn->as_f) || ferror(asn->as_f)) {
+				*status = EIO;
+				return 0;
+			}
+			break;
+		}
 		buf[sizeof(buf) - 1] = '\0';
 
 #ifdef AS_DEBUG_FILE
--- traceroute.c.orig	2013-06-17 11:18:23.000000000 +0700
+++ traceroute.c	2014-03-13 17:27:14.000000000 +0700
@@ -931,6 +931,8 @@
 			as_path = 0;
 		}
 	}
+	if (as_path)
+		signal(SIGPIPE, SIG_IGN);
 	
 #if	defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
 	if (setpolicy(sndsock, "in bypass") < 0)
@@ -1471,6 +1473,7 @@
 {
 	register struct ip *ip;
 	register int hlen;
+	int as, status;
 	char addr[INET_ADDRSTRLEN];
 
 	ip = (struct ip *) buf;
@@ -1479,8 +1482,24 @@
 
 	strlcpy(addr, inet_ntoa(from->sin_addr), sizeof(addr));
 
-	if (as_path)
-		Printf(" [AS%u]", as_lookup(asn, addr, AF_INET));
+	while(as_path) {
+		as = as_lookup(asn, addr, AF_INET, &status);
+		if (status) {
+			as_shutdown(asn);
+			asn = as_setup(as_server);
+			if (asn == NULL) {
+				Fprintf(stderr, "%s: as_setup failed, AS# lookups"
+						" disabled\n", prog);
+				(void)fflush(stderr);
+				as_path = 0;
+				break;
+			}
+			else
+				continue;
+		}
+		Printf(" [AS%u]", as);
+		break;
+	}
 
 	if (nflag)
 		Printf(" %s", addr);
>Release-Note:
>Audit-Trail:

From: Eugene Grosbein <eugen@grosbein.net>
To: bug-followup@FreeBSD.ORG
Cc:  
Subject: Re: bin/187526: [patch] traceroute -a breaks of "whois" socket timeout
Date: Mon, 31 Mar 2014 23:53:22 +0700

 This is a multi-part message in MIME format.
 --------------040008040404060404030001
 Content-Type: text/plain; charset=us-ascii
 Content-Transfer-Encoding: 7bit
 
 Here comes corrected version of patch that fixes traceroute6 too
 (and unbreaks world building).
 
 
 --------------040008040404060404030001
 Content-Type: text/plain; charset=KOI8-R;
  name="traceroute.diff"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: attachment;
  filename="traceroute.diff"
 
 --- contrib/traceroute/as.h.orig	2013-06-17 11:18:23.000000000 +0700
 +++ contrib/traceroute/as.h	2014-03-13 17:13:48.000000000 +0700
 @@ -31,5 +31,5 @@
   */
  
  void *as_setup(const char *);
 -unsigned int as_lookup(void *, char *, sa_family_t);
 +unsigned int as_lookup(void *, char *, sa_family_t, int *);
  void as_shutdown(void *);
 --- contrib/traceroute/as.c.orig	2013-06-17 11:18:23.000000000 +0700
 +++ contrib/traceroute/as.c	2014-03-13 17:37:51.000000000 +0700
 @@ -119,7 +119,7 @@ as_setup(const char *server)
  }
  
  unsigned int
 -as_lookup(void *_asn, char *addr, sa_family_t family)
 +as_lookup(void *_asn, char *addr, sa_family_t family, int *status)
  {
  	struct aslookup *asn = _asn;
  	char buf[1024];
 @@ -129,8 +129,17 @@ as_lookup(void *_asn, char *addr, sa_fam
  	as = 0;
  	rc = dlen = 0;
  	plen = (family == AF_INET6) ? 128 : 32;
 -	(void)fprintf(asn->as_f, "!r%s/%d,l\n", addr, plen);
 -	(void)fflush(asn->as_f);
 +	*status = fprintf(asn->as_f, "!r%s/%d,l\n", addr, plen);
 +	if (*status < 0) {
 +		*status = errno;
 +		return 0;
 +	}
 +	*status = fflush(asn->as_f);
 +	if (*status == EOF) {
 +		*status = errno;
 +		return 0;
 +	}
 +	*status = 0;
  
  #ifdef AS_DEBUG_FILE
  	if (asn->as_debug) {
 @@ -139,7 +148,14 @@ as_lookup(void *_asn, char *addr, sa_fam
  	}
  #endif /* AS_DEBUG_FILE */
  
 -	while (fgets(buf, sizeof(buf), asn->as_f) != NULL) {
 +	while (1) {
 +		if (fgets(buf, sizeof(buf), asn->as_f) == NULL) {
 +			if(feof(asn->as_f) || ferror(asn->as_f)) {
 +				*status = EIO;
 +				return 0;
 +			}
 +			break;
 +		}
  		buf[sizeof(buf) - 1] = '\0';
  
  #ifdef AS_DEBUG_FILE
 --- contrib/traceroute/traceroute.c.orig	2013-06-17 11:18:23.000000000 +0700
 +++ contrib/traceroute/traceroute.c	2014-03-13 17:27:14.000000000 +0700
 @@ -931,6 +931,8 @@
  			as_path = 0;
  		}
  	}
 +	if (as_path)
 +		signal(SIGPIPE, SIG_IGN);
  	
  #if	defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
  	if (setpolicy(sndsock, "in bypass") < 0)
 @@ -1471,6 +1473,7 @@
  {
  	register struct ip *ip;
  	register int hlen;
 +	int as, status;
  	char addr[INET_ADDRSTRLEN];
  
  	ip = (struct ip *) buf;
 @@ -1479,8 +1482,24 @@
  
  	strlcpy(addr, inet_ntoa(from->sin_addr), sizeof(addr));
  
 -	if (as_path)
 -		Printf(" [AS%u]", as_lookup(asn, addr, AF_INET));
 +	while(as_path) {
 +		as = as_lookup(asn, addr, AF_INET, &status);
 +		if (status) {
 +			as_shutdown(asn);
 +			asn = as_setup(as_server);
 +			if (asn == NULL) {
 +				Fprintf(stderr, "%s: as_setup failed, AS# lookups"
 +						" disabled\n", prog);
 +				(void)fflush(stderr);
 +				as_path = 0;
 +				break;
 +			}
 +			else
 +				continue;
 +		}
 +		Printf(" [AS%u]", as);
 +		break;
 +	}
  
  	if (nflag)
  		Printf(" %s", addr);
 --- usr.sbin/traceroute6/traceroute6.c.orig	2013-10-21 21:03:06.000000000 +0700
 +++ usr.sbin/traceroute6/traceroute6.c	2014-03-24 00:25:21.000000000 +0700
 @@ -885,6 +885,8 @@ main(argc, argv)
  			as_path = 0;
  		}
  	}
 +	if (as_path)
 +	        signal(SIGPIPE, SIG_IGN);
  
  	/*
  	 * Message to users
 @@ -1376,13 +1378,30 @@ print(mhdr, cc)
  	int cc;
  {
  	struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name;
 +	int as, status;
  	char hbuf[NI_MAXHOST];
  
  	if (getnameinfo((struct sockaddr *)from, from->sin6_len,
  	    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
  		strlcpy(hbuf, "invalid", sizeof(hbuf));
 -	if (as_path)
 -		printf(" [AS%u]", as_lookup(asn, hbuf, AF_INET6));
 +	while(as_path) {
 +		as = as_lookup(asn, hbuf, AF_INET6, &status);
 +		if (status) {
 +			as_shutdown(asn);
 +			asn = as_setup(as_server);
 +			if (asn == NULL) {
 +				fprintf(stderr, "traceroute6: as_setup failed, AS# lookups"
 +						" disabled\n");
 +				(void)fflush(stderr);
 +				as_path = 0;
 +				break;
 +			}
 +			else
 +				continue;
 +		}
 +		printf(" [AS%u]", as);
 +		break;
 +	}
  	if (nflag)
  		printf(" %s", hbuf);
  	else if (lflag)
 
 --------------040008040404060404030001--
>Unformatted:
