Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 09 Feb 2026 10:00:14 +0000
From:      Eugene Grosbein <eugen@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 60a6ebaf7371 - main - traceroute: graceful recover after networking errors with as_server
Message-ID:  <6989b02e.1c92d.ca70ad2@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by eugen:

URL: https://cgit.FreeBSD.org/src/commit/?id=60a6ebaf73719ef7aa15768c3906626fb106b2b3

commit 60a6ebaf73719ef7aa15768c3906626fb106b2b3
Author:     Eugene Grosbein <eugen@FreeBSD.org>
AuthorDate: 2026-02-09 09:47:01 +0000
Commit:     Eugene Grosbein <eugen@FreeBSD.org>
CommitDate: 2026-02-09 10:00:10 +0000

    traceroute: graceful recover after networking errors with as_server
    
    Currentlu, the traceroute[6] utility does not check
    for possible networking errors while talking to as_server
    in case of "traceroute -a". Meantime, there is a common case
    when trace is long and it has many non-responding hops
    (shown as '* * *'), so as_server aborts our connection,
    hence no AS numbers shown for the rest of trace.
    
    Somewhat artifical way to reproduce the problem:
    
    traceroute to 57.144.244.1 (57.144.244.1), 80 hops max, 48 byte packets
     5  [AS174] be2950.ccr42.fra05.atlas.cogentco.com (154.54.72.42)  74.277 ms  9.605 ms  9.599 ms
     6  [AS174] 149.11.228.19 (149.11.228.19)  9.506 ms  9.466 ms  9.420 ms
     7  [AS33182] po172.asw02.fra5.tfbnw.net (129.134.108.146)  9.725 ms  9.874 ms  9.696 ms
     8  [AS32934] psw04.fra5.tfbnw.net (157.240.59.85)  8.718 ms  8.691 ms  8.618 ms
     9  * * *
    10  [AS0] edge-star-mini-shv-01-fra5.facebook.com (57.144.244.1)  9.747 ms  9.815 ms  9.699 ms
    
    Note what due to increased timeout (-w10) we get [AS0] for 10th hop
    because as_server closed our connection. Same problem occurs
    with default -w3 when there are lots of '* * *' hops in a trace.
    
    Fix it with some additional error checking and a reconnection.
    
    This patch was in my use for many years and after traceroute(8) moved
    from contrib/ to usr.sbin/ it's nice to have it in the tree.
    
    MFC after:      2 weeks
---
 usr.sbin/traceroute/as.c           | 24 ++++++++++++++++++++----
 usr.sbin/traceroute/as.h           |  2 +-
 usr.sbin/traceroute/traceroute.c   | 21 +++++++++++++++++++--
 usr.sbin/traceroute6/traceroute6.c | 23 +++++++++++++++++++++--
 4 files changed, 61 insertions(+), 9 deletions(-)

diff --git a/usr.sbin/traceroute/as.c b/usr.sbin/traceroute/as.c
index 7fb952ed3da1..512f1dd6f14c 100644
--- a/usr.sbin/traceroute/as.c
+++ b/usr.sbin/traceroute/as.c
@@ -118,7 +118,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];
@@ -128,8 +128,17 @@ as_lookup(void *_asn, char *addr, sa_family_t family)
 	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) {
@@ -138,7 +147,14 @@ as_lookup(void *_asn, char *addr, sa_family_t family)
 	}
 #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
diff --git a/usr.sbin/traceroute/as.h b/usr.sbin/traceroute/as.h
index f5a5dae2acec..ac61bbab4786 100644
--- a/usr.sbin/traceroute/as.h
+++ b/usr.sbin/traceroute/as.h
@@ -30,5 +30,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 *);
diff --git a/usr.sbin/traceroute/traceroute.c b/usr.sbin/traceroute/traceroute.c
index 1297d3402ebd..be14c40b8d7b 100644
--- a/usr.sbin/traceroute/traceroute.c
+++ b/usr.sbin/traceroute/traceroute.c
@@ -1653,6 +1653,7 @@ print(register u_char *buf, register int cc, register struct sockaddr_in *from)
 {
 	register struct ip *ip;
 	register int hlen;
+	int as, status;
 	char addr[INET_ADDRSTRLEN];
 
 	ip = (struct ip *) buf;
@@ -1661,8 +1662,24 @@ print(register u_char *buf, register int cc, register struct sockaddr_in *from)
 
 	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);
diff --git a/usr.sbin/traceroute6/traceroute6.c b/usr.sbin/traceroute6/traceroute6.c
index 173e97c13bb3..eb6086706f9f 100644
--- a/usr.sbin/traceroute6/traceroute6.c
+++ b/usr.sbin/traceroute6/traceroute6.c
@@ -894,6 +894,8 @@ main(int argc, char *argv[])
 			as_path = 0;
 		}
 	}
+	if (as_path)
+	        signal(SIGPIPE, SIG_IGN);
 
 	/*
 	 * Message to users
@@ -1577,13 +1579,30 @@ void
 print(struct msghdr *mhdr, int cc)
 {
 	struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name;
+	int as, status;
 	char hbuf[NI_MAXHOST];
 
 	if (cap_getnameinfo(capdns, (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


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6989b02e.1c92d.ca70ad2>