]> git.ipfire.org Git - thirdparty/mtr.git/commitdiff
Add -D (--due-ttl) option. 546/head
authorDmitrii Allyanov <dvallyanov@gmail.com>
Wed, 10 Sep 2025 13:49:47 +0000 (13:49 +0000)
committerDmitrii Allyanov <dvallyanov@gmail.com>
Wed, 10 Sep 2025 13:49:47 +0000 (13:49 +0000)
Specifies the minimum TTL value that must be reached when sending network probes.

Closes feature request #295

man/mtr.8.in
ui/mtr.c
ui/mtr.h
ui/net.c

index 47c0cfee0a4874cfd50333898a9654b1a53247c0..5101094497b275ad37acf111483359092aea9ee4 100644 (file)
@@ -421,6 +421,12 @@ Specifies with what TTL to start.  Defaults to 1.
 Specifies the maximum number of hops (max time-to-live value) traceroute will
 probe.  Default is 30.
 .TP
+.B \-D \fINUM\fR, \fB\-\-due-ttl \fINUM
+Specifies the minimum TTL value to achieve when sending network probes.
+Default is disabled. However, if responses from the target host were received
+on hops less than the specified value, the host address will be displayed only
+in the ECMP section of the paths.
+.TP
 .B \-U \fINUM\fR, \fB\-\-max-unknown \fINUM
 Specifies the maximum unknown host. Default is 5.
 .TP
index 4d5a343d5957158a4b5dc26c5b9cd3e56f73039c..6886bce346c52adb60868055f9331c567dcf4e14 100644 (file)
--- a/ui/mtr.c
+++ b/ui/mtr.c
@@ -107,6 +107,7 @@ static void __attribute__ ((__noreturn__)) usage(FILE * out)
     fputs(" -a, --address ADDRESS            bind the outgoing socket to ADDRESS\n", out);  
     fputs(" -f, --first-ttl NUMBER           set what TTL to start\n", out);
     fputs(" -m, --max-ttl NUMBER             maximum number of hops\n", out);
+    fputs(" -D, --due-ttl NUMBER             set what TTL must be reached\n", out);
     fputs(" -U, --max-unknown NUMBER         maximum unknown host\n", out);
     fputs(" -E, --max-display-path NUMBER    maximum number of ECMP paths to display\n", out);
     fputs(" -P, --port PORT                  target port number for TCP, SCTP, or UDP\n", out);  
@@ -356,6 +357,7 @@ static void parse_arg(
         {"address", 1, NULL, 'a'},
         {"first-ttl", 1, NULL, 'f'},    /* -f & -m are borrowed from traceroute */
         {"max-ttl", 1, NULL, 'm'},
+        {"due-ttl", 1, NULL, 'D'},
         {"max-unknown", 1, NULL, 'U'},
         {"max-display-path", 1, NULL, 'E'},
         {"udp", 0, NULL, 'u'},  /* UDP (default is ICMP) */
@@ -497,6 +499,15 @@ static void parse_arg(
                 ctl->maxTTL = 1;
             }
             break;
+        case 'D':
+            ctl->dueTTL = strtoint_or_err(optarg, "invalid argument");
+            if (ctl->dueTTL > (MaxHost - 1)) {
+                ctl->dueTTL = MaxHost - 1;
+            }
+            if (ctl->dueTTL <= 0) {
+                error(EXIT_FAILURE, 0, "due TTL must be greater than 0");
+            }
+            break;
         case 'U':
             ctl->maxUnknown =
                 strtoint_or_err(optarg, "invalid argument");
@@ -652,6 +663,16 @@ static void parse_arg(
         exit (1);
         //ctl->fstTTL = ctl->maxTTL;
     }
+    if (ctl->dueTTL > 0 && ctl->dueTTL < ctl->fstTTL) {
+        fprintf (stderr, "%s: dueTTL(%d) cannot be less than firstTTL(%d). \n", 
+                argv[0], ctl->dueTTL, ctl->fstTTL);
+        exit (1);
+    }
+    if (ctl->dueTTL > ctl->maxTTL) {
+        fprintf (stderr, "%s: dueTTL(%d) cannot be larger than maxTTL(%d). \n", 
+                argv[0], ctl->dueTTL, ctl->maxTTL);
+        exit (1);
+    }
 
     if (optind > argc - 1)
         return;
@@ -751,6 +772,7 @@ int main(
     ctl.mtrtype = IPPROTO_ICMP;
     ctl.fstTTL = 1;
     ctl.maxTTL = 30;
+    ctl.dueTTL = 0;
     ctl.maxUnknown = 12;
     ctl.maxDisplayPath = 8;
     ctl.probe_timeout = 10 * 1000000;
index dcf02d705ed536343a61b9a86b1b97d54a44c415..038b7d23d560e74701ae980cc4a5d6cd10fd9816 100644 (file)
--- a/ui/mtr.h
+++ b/ui/mtr.h
@@ -102,6 +102,7 @@ struct mtr_ctl {
     int mtrtype;                /* type of query packet used */
     int fstTTL;                 /* initial hub(ttl) to ping byMin */
     int maxTTL;                 /* last hub to ping byMin */
+    int dueTTL;                 /* don't stop until reach dueTTL */
     int maxUnknown;             /* stop ping threshold */
     int maxDisplayPath;         /* maximum number of ECMP paths to display */
     int remoteport;             /* target port for TCP tracing */
index ce2c2c98b17c82efd8a029dec57ec93334d2971e..fe86c427ef3b081dec015cfc85f9825a91cb401d 100644 (file)
--- a/ui/net.c
+++ b/ui/net.c
@@ -258,12 +258,23 @@ static void net_process_ping(
             display_rawhost(ctl, index, &nh->addrs[i], mpls);
         }
 
-        /* Always save the latest host in nh->addr. This
+        /* Save the latest host in nh->addr only, if the answer was from remotehost and option -D enabled.
+           This allows to see responses coming through routes with different TTLs and from the target host.
+        */
+        if ((ctl->dueTTL > 0) && (addrcmp(&addrcopy, remoteaddress, ctl->af) == 0)) {
+           if (ctl->dueTTL <= (index + 1)) {
+                 memcpy(&nh->addr, addrcopy, sockaddr_addr_size(sourcesockaddr));
+                 nh->mpls = *mpls;
+                 display_rawhost(ctl, index, &nh->addr, mpls);
+           }
+        } else {
+        /* Save the latest host in nh->addr. This
          * allows maxTTL to change whenever path changes.
          */
         memcpy(&nh->addr, addrcopy, sockaddr_addr_size(sourcesockaddr));
         nh->mpls = *mpls;
         display_rawhost(ctl, index, &nh->addr, mpls);
+        }
     }
 
     nh->jitter = totusec - nh->last;
@@ -587,8 +598,9 @@ int net_send_batch(
            but I don't remember why. It makes mtr stop skipping sections of unknown
            hosts. Removed in 0.65.
            If the line proves necessary, it should at least NOT trigger that line
-           when host[i].addr == 0 */
-        if (host_addr_cmp(i, remoteaddress, ctl->af) == 0) {
+           when host[i].addr == 0
+           Keep this behavior if the newly added -D (dueTTL) option is not enabled */
+        if ((host_addr_cmp(i, remoteaddress, ctl->af) == 0) && (ctl->dueTTL == 0)) {
             restart = 1;
             numhosts = i + 1; /* Saves batch_at - index number of probes in the next round!*/
             break;
@@ -596,9 +608,9 @@ int net_send_batch(
     }
 
     if (                        /* success in reaching target */
-           (host_addr_cmp(batch_at, remoteaddress, ctl->af) == 0) ||
+           ((host_addr_cmp(batch_at, remoteaddress, ctl->af) == 0) && (ctl->dueTTL == 0)) ||
            /* fail in consecutive maxUnknown (firewall?) */
-           (n_unknown > ctl->maxUnknown) ||
+           ((n_unknown > ctl->maxUnknown) && (ctl->dueTTL == 0)) ||
            /* or reach limit  */
            (batch_at >= ctl->maxTTL - 1)) {
         restart = 1;