Since traceroute is capable to handle ICMP extensions as described in RFC
4884. RFC 5837 "Extending ICMP for Interface and Next-Hop Identification"
adds a way to include more information about incomming/outgoing interface
into the ICMP.

While there I tried to cleanup the MPLS output a bit to make it shorter by
default. Print "Label" once and show the experimental bits only when
non-zero.

The RFC 5837 part is untested since I could not find a system adding this
information.
-- 
:wq Claudio

Index: traceroute.c
===================================================================
RCS file: /cvs/src/usr.sbin/traceroute/traceroute.c,v
retrieving revision 1.72
diff -u -p -r1.72 traceroute.c
--- traceroute.c        9 Jul 2010 12:27:09 -0000       1.72
+++ traceroute.c        7 Sep 2010 14:37:48 -0000
@@ -728,7 +728,9 @@ print_exthdr(u_char *buf, int cc)
        struct ip *ip;
        struct icmp *icp;
        int hlen, first;
-       u_int32_t label;
+       u_int32_t label, ifindex, mtu;
+       struct in_addr addr;
+       char *name;
        u_int16_t off, olen;
        u_int8_t type;
                        
@@ -805,13 +807,14 @@ print_exthdr(u_char *buf, int cc)
                                        olen -= sizeof(u_int32_t);
                                        
                                        if (first == 0) {
-                                               printf(" [MPLS: ");
+                                               printf(" [MPLS Label ");
                                                first++;
                                        } else
                                                printf(", ");
-                                       printf("Label %d Exp %d",
-                                               MPLS_LABEL(label), 
-                                               MPLS_EXP(label));
+                                       printf("%d", MPLS_LABEL(label));
+                                       if (MPLS_EXP(label))
+                                               printf(" (Exp %x)",
+                                                   MPLS_EXP(label));
                                }
                                if (olen > 0) {
                                        printf("|]");
@@ -826,6 +829,91 @@ print_exthdr(u_char *buf, int cc)
                        }
                        break;
                case ICMP_EXT_IFINFO:
+                       /* RFC 5837: Extending ICMP for Interface and Next-Hop
+                        * Identification */
+                       mtu = 0;
+                       ifindex = 0;
+                       addr.s_addr = INADDR_ANY;
+                       name = NULL;
+                       if (objhdr.ieo_ctype & 0x80)
+                               printf("(fwd");
+                       else
+                               printf("(recv");
+                       /* must parse in this order */
+                       if (objhdr.ieo_ctype & 0x08) {
+                               /* ifIndex */
+                               if (olen < sizeof(u_int32_t)) {
+                                       printf("|)");
+                                       return;
+                               }
+                               memcpy(&ifindex, buf, sizeof(u_int32_t));
+                               ifindex = ntohl(ifindex);
+                               buf += sizeof(u_int32_t);
+                               olen -= sizeof(u_int32_t);
+                       }
+                       if (objhdr.ieo_ctype & 0x04) {
+                               /* IPAddr */
+                               u_int16_t afi;
+
+                               if (olen < sizeof(u_int32_t)) {
+                                       printf("|)");
+                                       return;
+                               }
+                               memcpy(&afi, buf, sizeof(u_int16_t));
+                               afi = ntohs(afi);
+                               if (afi != 1 /* AFI_IPv4 */) {
+                                       printf("afi|)");
+                                       return;
+                               }
+                               buf += sizeof(u_int32_t);
+                               olen -= sizeof(u_int32_t);
+
+                               if (olen < sizeof(u_int32_t)) {
+                                       printf("|)");
+                                       return;
+                               }
+                               memcpy(&addr, buf, sizeof(u_int32_t));
+                               buf += sizeof(u_int32_t);
+                               olen -= sizeof(u_int32_t);
+                       }
+                       if (objhdr.ieo_ctype & 0x02) {
+                               /* interface name */
+                               if (olen < buf[0]) {
+                                       printf("|)");
+                                       return;
+                               }
+                               name = strndup(buf + 1, buf[0]);
+                               olen -= buf[0];
+                               buf += buf[0];
+                       }
+                       if (objhdr.ieo_ctype & 0x01) {
+                               /* MTU */
+                               if (olen < sizeof(u_int32_t)) {
+                                       printf("|)");
+                                       return;
+                               }
+
+                               memcpy(&mtu, buf, sizeof(u_int32_t));
+                               mtu = ntohl(mtu);
+
+                               buf += sizeof(u_int32_t);
+                               olen -= sizeof(u_int32_t);
+                       }
+
+                       if (ifindex && name == NULL)
+                               asprintf(&name, " ifidx %d", ifindex);
+
+                       if (name)
+                               printf("%s", name);
+                       if (addr.s_addr != INADDR_ANY)
+                               printf("%s%s", name ? ": " : " ",
+                                   inet_ntoa(addr));
+                       if (mtu)
+                               printf("MTU %d", mtu);
+                       printf(")");
+
+                       free(name);
+                       break;
                default:
                        buf += olen;
                        break;

Reply via email to