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;
