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
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 *);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user