diff options
author | 2010-07-08 20:23:03 +0000 | |
---|---|---|
committer | 2010-07-08 20:23:03 +0000 | |
commit | 0b10b01e8e15d57aff52e3e07464f293a02d35fe (patch) | |
tree | 00e5c3f57d3c87d636b52d2beb9f8f528af2e916 | |
parent | Add definitions for ICMP extended headers available for some ICMP messages (diff) | |
download | wireguard-openbsd-0b10b01e8e15d57aff52e3e07464f293a02d35fe.tar.xz wireguard-openbsd-0b10b01e8e15d57aff52e3e07464f293a02d35fe.zip |
Let traceroute parse extended ICMP messages as defined by RFC 4884.
Currently only the MPLS label can be shown (RFC 4950). The extended
information is only printed if either -x or -v was used.
Initialy based on a port from NetBSD done by dhill@ but mostly rewritten now.
OK deraadt@, dhill@
-rw-r--r-- | usr.sbin/traceroute/traceroute.8 | 8 | ||||
-rw-r--r-- | usr.sbin/traceroute/traceroute.c | 138 |
2 files changed, 137 insertions, 9 deletions
diff --git a/usr.sbin/traceroute/traceroute.8 b/usr.sbin/traceroute/traceroute.8 index fcc4a417446..d699c7543d8 100644 --- a/usr.sbin/traceroute/traceroute.8 +++ b/usr.sbin/traceroute/traceroute.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: traceroute.8,v 1.43 2010/07/03 04:44:52 guenther Exp $ +.\" $OpenBSD: traceroute.8,v 1.44 2010/07/08 20:23:03 claudio Exp $ .\" $NetBSD: traceroute.8,v 1.6 1995/10/12 03:05:50 mycroft Exp $ .\" .\" Copyright (c) 1990, 1991, 1993 @@ -33,7 +33,7 @@ .\" .\" @(#)traceroute.8 8.1 (Berkeley) 6/6/93 .\" -.Dd $Mdocdate: July 3 2010 $ +.Dd $Mdocdate: July 8 2010 $ .Dt TRACEROUTE 8 .Os .Sh NAME @@ -42,7 +42,7 @@ .Sh SYNOPSIS .Nm traceroute .Bk -words -.Op Fl cDdIlnrSv +.Op Fl cDdIlnrSvx .Op Fl f Ar first_ttl .Op Fl g Ar gateway_addr .Op Fl m Ar max_ttl @@ -205,6 +205,8 @@ and are listed. .It Fl w Ar waittime Set the time (in seconds) to wait for a response to a probe (default 5). +.It Fl x +Print the ICMP extended headers if available. .El .Pp This program attempts to trace the route an IP packet would follow to some diff --git a/usr.sbin/traceroute/traceroute.c b/usr.sbin/traceroute/traceroute.c index 5a142aabd94..1c3771fa230 100644 --- a/usr.sbin/traceroute/traceroute.c +++ b/usr.sbin/traceroute/traceroute.c @@ -1,4 +1,4 @@ -/* $OpenBSD: traceroute.c,v 1.70 2010/07/05 21:44:48 robert Exp $ */ +/* $OpenBSD: traceroute.c,v 1.71 2010/07/08 20:23:03 claudio Exp $ */ /* $NetBSD: traceroute.c,v 1.10 1995/05/21 15:50:45 mycroft Exp $ */ /*- @@ -220,6 +220,8 @@ #include <arpa/inet.h> +#include <netmpls/mpls.h> + #include <ctype.h> #include <err.h> #include <errno.h> @@ -229,7 +231,10 @@ #include <string.h> #include <unistd.h> -#define MAX_LSRR ((MAX_IPOPTLEN - 4) / 4) +#define MAX_LSRR ((MAX_IPOPTLEN - 4) / 4) + +#define MPLS_LABEL(m) ((m & MPLS_LABEL_MASK) >> MPLS_LABEL_OFFSET) +#define MPLS_EXP(m) ((m & MPLS_EXP_MASK) >> MPLS_EXP_OFFSET) /* * Format of the data in a (udp) probe packet. @@ -252,6 +257,7 @@ u_char packet[512], *outpacket; /* last inbound (icmp) packet */ int wait_for_reply(int, struct sockaddr_in *, struct timeval *); void send_probe(int, u_int8_t, int, struct sockaddr_in *); int packet_ok(u_char *, int, struct sockaddr_in *, int, int); +void print_exthdr(u_char *, int); void print(u_char *, int, struct sockaddr_in *); char *inetname(struct in_addr); u_short in_cksum(u_short *, int); @@ -279,6 +285,7 @@ int verbose; int waittime = 5; /* time to wait for response (in seconds) */ int nflag; /* print addresses numerically */ int dump; +int xflag; /* show ICMP extension header */ int main(int argc, char *argv[]) @@ -311,7 +318,8 @@ main(int argc, char *argv[]) (void) sysctl(mib, sizeof(mib)/sizeof(mib[0]), &max_ttl, &size, NULL, 0); - while ((ch = getopt(argc, argv, "cDdf:g:Ilm:nP:p:q:rSs:t:V:vw:")) != -1) + while ((ch = getopt(argc, argv, "cDdf:g:Ilm:nP:p:q:rSs:t:V:vw:x")) + != -1) switch (ch) { case 'S': sump = 1; @@ -445,6 +453,9 @@ main(int argc, char *argv[]) errx(1, "wait must be >1 sec."); waittime = (int)l; break; + case 'x': + xflag = 1; + break; default: usage(); } @@ -695,7 +706,9 @@ main(int argc, char *argv[]) printf(" *"); timeout++; loss++; - } + } else if (cc && probe == nprobes - 1 && + (xflag || verbose)) + print_exthdr(packet, cc); (void) fflush(stdout); } if (sump) @@ -707,6 +720,119 @@ main(int argc, char *argv[]) exit(0); } +void +print_exthdr(u_char *buf, int cc) +{ + struct icmp_ext_hdr exthdr; + struct icmp_ext_obj_hdr objhdr; + struct ip *ip; + struct icmp *icp; + int hlen, first; + u_int32_t label; + u_int16_t off, olen; + u_int8_t type; + + ip = (struct ip *)buf; + hlen = ip->ip_hl << 2; + if (cc < hlen + ICMP_MINLEN) + return; + icp = (struct icmp *)(buf + hlen); + cc -= hlen + ICMP_MINLEN; + buf += hlen + ICMP_MINLEN; + + type = icp->icmp_type; + if (type != ICMP_TIMXCEED && type != ICMP_UNREACH && + type != ICMP_PARAMPROB) + /* Wrong ICMP type for extension */ + return; + + off = icp->icmp_length * sizeof(u_int32_t); + if (off == 0) + /* + * rfc 4884 Section 5.5: traceroute MUST try to parse + * broken ext headers. Again IETF bent over to please + * idotic corporations. + */ + off = ICMP_EXT_OFFSET; + else if (off < 128) + /* rfc 4884 requires an offset of at least 128 bytes */ + return; + + /* make sure that at least one extension is present */ + if (cc < off + sizeof(exthdr) + sizeof(objhdr)) + /* Not enough space for ICMP extensions */ + return; + + cc -= off; + buf += off; + memcpy(&exthdr, buf, sizeof(exthdr)); + + /* verify version */ + if ((exthdr.ieh_version & ICMP_EXT_HDR_VMASK) != ICMP_EXT_HDR_VERSION) + return; + + /* verify checksum */ + if (exthdr.ieh_cksum && in_cksum((u_short *)buf, cc)) + return; + + buf += sizeof(exthdr); + cc -= sizeof(exthdr); + + while (cc > sizeof(objhdr)) { + memcpy(&objhdr, buf, sizeof(objhdr)); + olen = ntohs(objhdr.ieo_length); + + /* Sanity check the length field */ + if (olen < sizeof(objhdr) || olen > cc) + return; + + cc -= olen; + + /* Move past the object header */ + buf += sizeof(objhdr); + olen -= sizeof(objhdr); + + switch (objhdr.ieo_cnum) { + case ICMP_EXT_MPLS: + /* RFC 4950: ICMP Extensions for MPLS */ + switch (objhdr.ieo_ctype) { + case 1: + first = 0; + while (olen >= sizeof(u_int32_t)) { + memcpy(&label, buf, sizeof(u_int32_t)); + label = htonl(label); + buf += sizeof(u_int32_t); + olen -= sizeof(u_int32_t); + + if (first == 0) { + printf(" [MPLS: "); + first++; + } else + printf(", "); + printf("Label %d Exp %d", + MPLS_LABEL(label), + MPLS_EXP(label)); + } + if (olen > 0) { + printf("|]"); + return; + } + if (first != 0) + printf("]"); + break; + default: + buf += olen; + break; + } + break; + case ICMP_EXT_IFINFO: + default: + buf += olen; + break; + } + } +} + int wait_for_reply(int sock, struct sockaddr_in *from, struct timeval *sent) { @@ -964,7 +1090,7 @@ print(u_char *buf, int cc, struct sockaddr_in *from) inet_ntoa(from->sin_addr)); if (verbose) - printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst)); + printf(" %d bytes to %s", cc, inet_ntoa(ip->ip_dst)); } @@ -1040,7 +1166,7 @@ usage(void) extern char *__progname; fprintf(stderr, - "usage: %s [-cDdIlnrSv] [-f first_ttl] [-g gateway_addr] [-m max_ttl]\n" + "usage: %s [-cDdIlnrSvx] [-f first_ttl] [-g gateway_addr] [-m max_ttl]\n" "\t[-P proto] [-p port] [-q nqueries] [-s src_addr] [-t tos]\n" "\t[-V rtable] [-w waittime] host [packetsize]\n", __progname); exit(1); |