git: b3772accd926 - stable/14 - traceroute: Implement ECN bleaching detection

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Fri, 02 Feb 2024 14:39:33 UTC
The branch stable/14 has been updated by markj:

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

commit b3772accd92642440c0e7ed79621ab4138c3db7c
Author:     Jose Luis Duran <jlduran@gmail.com>
AuthorDate: 2023-10-28 00:28:52 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2024-02-02 14:32:24 +0000

    traceroute: Implement ECN bleaching detection
    
    Explicit Congestion Notification (ECN) is a mechanism that allows
    end-to-end notification of network congestion without dropping packets
    by explicitly setting the ECN code point (2 bits).
    
    Per RFC 8087, section 3.5, network devices should not be configured to
    change the ECN code point in the packets that they forward, except to
    set the CE (Congestion Experienced) code point ('11') to signal
    incipient congestion.
    
    The current commit adds an -E flag to traceroute that crafts a packet
    with an ECT(1) code point ('01').
    
    If the packet is received back with a zero ECN code point ('00'), it
    outputs that the hop in question erases or "bleaches" the ECN code point
    values.  Bleaching may occur for various reasons (including normalizing
    packets to hide which equipment supports ECN).  This policy prevents the
    use of ECN by applications.
    
    If the packet is received back with an all-ones ECN code point ('11'),
    it outputs that the hop in question is experiencing "congestion".
    
    If the packet is received back with a different ECN code point ('10'),
    it outputs that the hop in question changes or "mangles" the ECN code
    point values.
    
    If the packet is received with the same ECN code point that was sent
    ('01'), it outputs that the hop has "passed" the ECN bits appropriately.
    
    Inspired by:    Darwin
    Reviewed by:    imp, markj
    MFC after:      1 month
    Pull Request:   https://github.com/freebsd/freebsd-src/pull/879
    
    (cherry picked from commit 8aafae66394fe64489d6371c22da5a5fb7ee7c81)
---
 contrib/traceroute/traceroute.8 | 20 ++++++++++++++++++--
 contrib/traceroute/traceroute.c | 30 ++++++++++++++++++++++++++++--
 2 files changed, 46 insertions(+), 4 deletions(-)

diff --git a/contrib/traceroute/traceroute.8 b/contrib/traceroute/traceroute.8
index 85a7e9d3a17e..21427ef6e97c 100644
--- a/contrib/traceroute/traceroute.8
+++ b/contrib/traceroute/traceroute.8
@@ -16,7 +16,7 @@
 .\"	$Id: traceroute.8,v 1.19 2000/09/21 08:44:19 leres Exp $
 .\"	$FreeBSD$
 .\"
-.Dd November 25, 2020
+.Dd October 25, 2023
 .Dt TRACEROUTE 8
 .Os
 .Sh NAME
@@ -25,7 +25,7 @@
 .Sh SYNOPSIS
 .Nm
 .Bk -words
-.Op Fl adDeFISnrvx
+.Op Fl adDeEFISnrvx
 .Op Fl f Ar first_ttl
 .Op Fl g Ar gateway
 .Op Fl M Ar first_ttl
@@ -67,6 +67,22 @@ default.
 Firewall evasion mode.
 Use fixed destination ports for UDP, UDP-Lite, TCP and SCTP probes.
 The destination port does NOT increment with each packet sent.
+.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 first_ttl
 Set the initial time-to-live used in the first outgoing probe packet.
 .It Fl F
diff --git a/contrib/traceroute/traceroute.c b/contrib/traceroute/traceroute.c
index fc87575ea043..6f2350150bd8 100644
--- a/contrib/traceroute/traceroute.c
+++ b/contrib/traceroute/traceroute.c
@@ -365,6 +365,7 @@ int doipcksum = 1;		/* calculate ip checksums by default */
 int optlen;			/* length of ip options */
 int fixedPort = 0;		/* Use fixed destination port for TCP and UDP */
 int printdiff = 0;		/* Print the difference between sent and quoted */
+int ecnflag = 0;		/* ECN bleaching detection flag */
 
 extern int optind;
 extern int opterr;
@@ -597,7 +598,7 @@ main(int argc, char **argv)
 		prog = argv[0];
 
 	opterr = 0;
-	while ((op = getopt(argc, argv, "aA:edDFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF)
+	while ((op = getopt(argc, argv, "aA:eEdDFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF)
 		switch (op) {
 		case 'a':
 			as_path = 1;
@@ -620,6 +621,10 @@ main(int argc, char **argv)
 			fixedPort = 1;
 			break;
 
+		case 'E':
+			ecnflag = 1;
+			break;
+
 		case 'f':
 		case 'M':	/* FreeBSD compat. */
 			first_ttl = str2val(optarg, "first ttl", 1, 255);
@@ -784,6 +789,10 @@ main(int argc, char **argv)
 	outip->ip_v = IPVERSION;
 	if (settos)
 		outip->ip_tos = tos;
+	if (ecnflag) {
+		outip->ip_tos &= ~IPTOS_ECN_MASK;
+		outip->ip_tos |= IPTOS_ECN_ECT1;
+	}
 #ifdef BYTESWAP_IP_HDR
 	outip->ip_len = htons(packlen);
 	outip->ip_off = htons(off);
@@ -1122,6 +1131,23 @@ main(int argc, char **argv)
 #endif
 					precis = 3;
 				Printf("  %.*f ms", precis, T);
+				if (ecnflag) {
+					u_char ecn = hip->ip_tos & IPTOS_ECN_MASK;
+					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 (printdiff) {
 					Printf("\n");
 					Printf("%*.*s%s\n",
@@ -2126,7 +2152,7 @@ usage(void)
 
 	Fprintf(stderr, "Version %s\n", version);
 	Fprintf(stderr,
-	    "Usage: %s [-adDeFInrSvx] [-f first_ttl] [-g gateway] [-i iface]\n"
+	    "Usage: %s [-adDeEFInrSvx] [-f first_ttl] [-g gateway] [-i iface]\n"
 	    "\t[-m max_ttl] [-p port] [-P proto] [-q nqueries] [-s src_addr]\n"
 	    "\t[-t tos] [-w waittime] [-A as_server] [-z pausemsecs] host [packetlen]\n", prog);
 	exit(1);