diff --git a/usr.sbin/traceroute6/traceroute6.8 b/usr.sbin/traceroute6/traceroute6.8 index f02b08872ea..13917eb47c7 100644 --- a/usr.sbin/traceroute6/traceroute6.8 +++ b/usr.sbin/traceroute6/traceroute6.8 @@ -27,7 +27,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd November 25, 2020 +.Dd October 25, 2023 .Dt TRACEROUTE6 8 .Os .\" @@ -38,7 +38,7 @@ .Sh SYNOPSIS .Nm .Bk -words -.Op Fl adIlnNrSTUv +.Op Fl adEIlnNrSTUv .Ek .Bk -words .Op Fl f Ar firsthop @@ -94,6 +94,22 @@ Turn on AS# lookups for each hop encountered. Turn on AS# lookups and use the given server instead of the default. .It Fl d Debug mode. +.It Fl E +Detect ECN bleaching. +Set the +.Em IPTOS_ECN_ECT1 +Explicit Congestion Notification (ECN) bits +.Pq Dv 01 , +and report if the hop has bleached +.Pq Dv 00 +or mangled +.Pq Dv 10 +them, or if it is experiencing congestion +.Pq Dv 11 . +Otherwise, report that it passed the bits appropriately. +If +.Fl t +is also specified, the corresponding ECN bits will be replaced. .It Fl f Ar firsthop Specify how many hops to skip in trace. .It Fl g Ar gateway diff --git a/usr.sbin/traceroute6/traceroute6.c b/usr.sbin/traceroute6/traceroute6.c index 7907952e932..1f5fc0a6b3a 100644 --- a/usr.sbin/traceroute6/traceroute6.c +++ b/usr.sbin/traceroute6/traceroute6.c @@ -274,6 +274,7 @@ static char sccsid[] = "@(#)traceroute.c 8.1 (Berkeley) 6/6/93"; #include #include +#include #include #include #include @@ -306,7 +307,7 @@ void capdns_open(void); int get_hoplim(struct msghdr *); double deltaT(struct timeval *, struct timeval *); const char *pr_type(int); -int packet_ok(struct msghdr *, int, int, u_char *, u_char *); +int packet_ok(struct msghdr *, int, int, u_char *, u_char *, u_char *); void print(struct msghdr *, int); const char *inetname(struct sockaddr *); u_int32_t sctp_crc32c(void *, u_int32_t); @@ -352,6 +353,7 @@ static int nflag; /* print addresses numerically */ static int useproto = IPPROTO_UDP; /* protocol to use to send packet */ static int lflag; /* print both numerical address & hostname */ static int as_path; /* print as numbers for each hop */ +static int ecnflag; /* ECN bleaching detection flag */ static char *as_server = NULL; static void *asn; @@ -367,7 +369,7 @@ main(int argc, char *argv[]) struct hostent *hp; size_t size, minlen; uid_t uid; - u_char type, code; + u_char type, code, ecn; #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) char ipsec_inpolicy[] = "in bypass"; char ipsec_outpolicy[] = "out bypass"; @@ -413,7 +415,7 @@ main(int argc, char *argv[]) seq = 0; ident = htons(getpid() & 0xffff); /* same as ping6 */ - while ((ch = getopt(argc, argv, "aA:df:g:Ilm:nNp:q:rs:St:TUvw:")) != -1) + while ((ch = getopt(argc, argv, "aA:dEf:g:Ilm:nNp:q:rs:St:TUvw:")) != -1) switch (ch) { case 'a': as_path = 1; @@ -425,6 +427,9 @@ main(int argc, char *argv[]) case 'd': options |= SO_DEBUG; break; + case 'E': + ecnflag = 1; + break; case 'f': ep = NULL; errno = 0; @@ -596,6 +601,15 @@ main(int argc, char *argv[]) exit(1); } + if (ecnflag) { + if (tclass != -1) { + tclass &= ~IPTOS_ECN_MASK; + } else { + tclass = 0; + } + tclass |= IPTOS_ECN_ECT1; + } + /* revoke privs */ uid = getuid(); if (setresuid(uid, uid, uid) == -1) { @@ -960,7 +974,7 @@ main(int argc, char *argv[]) send_probe(++seq, hops); while ((cc = wait_for_reply(rcvsock, &rcvmhdr))) { (void) gettimeofday(&t2, NULL); - if (packet_ok(&rcvmhdr, cc, seq, &type, &code)) { + if (packet_ok(&rcvmhdr, cc, seq, &type, &code, &ecn)) { if (!IN6_ARE_ADDR_EQUAL(&Rcv.sin6_addr, &lastaddr)) { if (probe > 0) @@ -969,6 +983,22 @@ main(int argc, char *argv[]) lastaddr = Rcv.sin6_addr; } printf(" %.3f ms", deltaT(&t1, &t2)); + if (ecnflag) { + switch (ecn) { + case IPTOS_ECN_ECT1: + printf(" (ecn=passed)"); + break; + case IPTOS_ECN_NOTECT: + printf(" (ecn=bleached)"); + break; + case IPTOS_ECN_CE: + printf(" (ecn=congested)"); + break; + default: + printf(" (ecn=mangled)"); + break; + } + } if (type == ICMP6_DST_UNREACH) { switch (code) { case ICMP6_DST_UNREACH_NOROUTE: @@ -1302,7 +1332,8 @@ pr_type(int t0) } int -packet_ok(struct msghdr *mhdr, int cc, int seq, u_char *type, u_char *code) +packet_ok(struct msghdr *mhdr, int cc, int seq, u_char *type, u_char *code, + u_char *ecn) { struct icmp6_hdr *icp; struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name; @@ -1385,6 +1416,7 @@ packet_ok(struct msghdr *mhdr, int cc, int seq, u_char *type, u_char *code) void *up; hip = (struct ip6_hdr *)(icp + 1); + *ecn = ntohl(hip->ip6_flow & IPV6_ECN_MASK) >> 20; if ((up = get_uphdr(hip, (u_char *)(buf + cc))) == NULL) { if (verbose) warnx("failed to get upper layer header"); @@ -1804,7 +1836,7 @@ usage(void) { fprintf(stderr, -"usage: traceroute6 [-adIlnNrSTUv] [-A as_server] [-f firsthop] [-g gateway]\n" +"usage: traceroute6 [-adEIlnNrSTUv] [-A as_server] [-f firsthop] [-g gateway]\n" " [-m hoplimit] [-p port] [-q probes] [-s src] [-w waittime] target\n" " [datalen]\n"); exit(1);