Subject: bin/22523: traceroute icmp extensions patch
To: None <gnats-bugs@gnats.netbsd.org>
From: None <ww@parc.styx.org>
List: netbsd-bugs
Date: 08/11/2003 05:51:45
>Number: 22523
>Category: bin
>Synopsis: patch for traceroute to show mpls icmp extensions
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: bin-bug-people
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Mon Aug 18 03:29:00 UTC 2003
>Closed-Date:
>Last-Modified:
>Originator:
>Release: NetBSD 1.6
>Organization:
>Environment:
System: NetBSD styx.org 1.6 NetBSD 1.6 (STYX) #1: Thu Sep 26 04:10:32 EDT 2002 root@styx.org:/usr/src/sys/arch/macppc/compile/STYX macppc
Architecture: powerpc
Machine: macppc
>Description:
Patch from Jesper Skriver to make traceroute show mpls labels
if it recieves icmp packets with extensions defined in
http://www.watersprings.org/links/mlr/id/draft-ietf-mpls-icmp-01.txt
Original patch is http://e.wheel.dk/~jesper/traceroute.diff
modified slightly to make it apply cleanly to NetBSD source.
>How-To-Repeat:
>Fix:
Common subdirectories: /usr/src/usr.sbin/traceroute/CVS and traceroute/CVS
diff -u /usr/src/usr.sbin/traceroute/traceroute.c traceroute/traceroute.c
--- /usr/src/usr.sbin/traceroute/traceroute.c Fri Jan 11 16:42:58 2002
+++ traceroute/traceroute.c Mon Aug 11 05:41:57 2003
@@ -272,6 +272,55 @@
struct timeval tv; /* time packet left */
};
+/*
+ * Support for ICMP extensions
+ *
+ * http://www.ietf.org/proceedings/01aug/I-D/draft-ietf-mpls-icmp-02.txt
+ */
+#define ICMP_EXT_OFFSET 8 /* ICMP type, code, checksum, unused */ + \
+ 128 /* original datagram */
+#define ICMP_EXT_VERSION 2
+/*
+ * ICMP extensions, common header
+ */
+struct icmp_ext_cmn_hdr {
+#if BYTE_ORDER == BIG_ENDIAN
+ u_char version:4;
+ u_char reserved1:4;
+#else
+ u_char reserved1:4;
+ u_char version:4;
+#endif
+ u_char reserved2;
+ u_short checksum;
+};
+
+/*
+ * ICMP extensions, object header
+ */
+struct icmp_ext_obj_hdr {
+ u_short length;
+ u_char class_num;
+#define MPLS_STACK_ENTRY_CLASS 1
+ u_char c_type;
+#define MPLS_STACK_ENTRY_C_TYPE 1
+};
+
+struct mpls_header {
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int32_t label:20;
+ u_char exp:3;
+ u_char s:1;
+ u_char ttl:8;
+#else
+ u_char ttl:8;
+ u_char s:1;
+ u_char exp:3;
+ u_int32_t label:20;
+#endif
+};
+
+
u_char packet[512]; /* last inbound (icmp) packet */
struct ip *outip; /* last output (udp) packet */
@@ -373,6 +422,7 @@
int wait_for_reply(int, struct sockaddr_in *, struct timeval *);
void frag_err(void);
int find_local_ip(struct sockaddr_in *, struct sockaddr_in *);
+void decode_extensions(u_char *buf, int ip_len);
#ifdef IPSEC
#ifdef IPSEC_POLICY_IPSEC
int setpolicy(int so, char *policy);
@@ -1014,6 +1064,8 @@
}
if (cc == 0)
Printf(" *");
+ if (cc && probe == nprobes-1)
+ decode_extensions(packet, cc);
(void)fflush(stdout);
}
putchar('\n');
@@ -1026,6 +1078,118 @@
as_shutdown(asn);
exit(0);
+}
+
+void
+decode_extensions(u_char *buf, int ip_len)
+{
+ struct icmp_ext_cmn_hdr *cmn_hdr;
+ struct icmp_ext_obj_hdr *obj_hdr;
+ struct mpls_header *mpls;
+ int datalen, obj_len;
+ u_int32_t mpls_h;
+ struct ip *ip;
+
+ ip = (struct ip *)buf;
+
+ if (ip_len <= sizeof(struct ip) + ICMP_EXT_OFFSET) {
+ /*
+ * No support for ICMP extensions on this host
+ */
+ return;
+ }
+
+ /*
+ * Move forward to the start of the ICMP extensions, if present
+ */
+ buf += (ip->ip_hl << 2) + ICMP_EXT_OFFSET;
+ cmn_hdr = (struct icmp_ext_cmn_hdr *)buf;
+
+ if (cmn_hdr->version != ICMP_EXT_VERSION) {
+ /*
+ * Unknown version
+ */
+ return;
+ }
+
+ datalen = ip_len - ((u_char *)cmn_hdr - (u_char *)ip);
+
+ /*
+ * Check the checksum, cmn_hdr->checksum == 0 means no checksum'ing
+ * done by sender.
+ *
+ * If the checksum is ok, we'll get 0, as the checksum is calculated
+ * with the checksum field being 0'd.
+ */
+ if (ntohs(cmn_hdr->checksum) &&
+ in_cksum((u_short *)cmn_hdr, datalen)) {
+
+ return;
+ }
+
+ buf += sizeof(*cmn_hdr);
+ datalen -= sizeof(*cmn_hdr);
+
+ while (datalen > 0) {
+ obj_hdr = (struct icmp_ext_obj_hdr *)buf;
+ obj_len = ntohs(obj_hdr->length);
+
+ /*
+ * Sanity check the length field
+ */
+ if (obj_len > datalen) {
+ return;
+ }
+
+ datalen -= obj_len;
+
+ /*
+ * Move past the object header
+ */
+ buf += sizeof(struct icmp_ext_obj_hdr);
+ obj_len -= sizeof(struct icmp_ext_obj_hdr);
+
+ switch (obj_hdr->class_num) {
+ case MPLS_STACK_ENTRY_CLASS:
+ switch (obj_hdr->c_type) {
+ case MPLS_STACK_ENTRY_C_TYPE:
+ while (obj_len >= sizeof(u_int32_t)) {
+ mpls_h = ntohl(*(u_int32_t *)buf);
+
+ buf += sizeof(u_int32_t);
+ obj_len -= sizeof(u_int32_t);
+
+ mpls = (struct mpls_header *) &mpls_h;
+ printf("\n MPLS Label=%d CoS=%d TTL=%d S=%d",
+ mpls->label, mpls->exp, mpls->ttl, mpls->s);
+ }
+ if (obj_len > 0) {
+ /*
+ * Something went wrong, and we're at a unknown offset
+ * into the packet, ditch the rest of it.
+ */
+ return;
+ }
+ break;
+ default:
+ /*
+ * Unknown object, skip past it
+ */
+ buf += ntohs(obj_hdr->length) -
+ sizeof(struct icmp_ext_obj_hdr);
+ break;
+ }
+ break;
+
+ default:
+ /*
+ * Unknown object, skip past it
+ */
+ buf += ntohs(obj_hdr->length) -
+ sizeof(struct icmp_ext_obj_hdr);
+ break;
+ }
+ }
}
int
>Release-Note:
>Audit-Trail:
>Unformatted: