aboutsummaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
authorDavid Malone <dwmalone@FreeBSD.org>2006-10-15 17:34:51 +0000
committerDavid Malone <dwmalone@FreeBSD.org>2006-10-15 17:34:51 +0000
commit2f87bd055e6c416227b29d589fa480e54649e488 (patch)
tree34337bd59c20aa414d2c580a6a964aa1312ab9a3 /contrib
parentb84baf83b944545d29c071f6aec30454a162aa98 (diff)
downloadsrc-2f87bd055e6c416227b29d589fa480e54649e488.tar.gz
src-2f87bd055e6c416227b29d589fa480e54649e488.zip
Add a -D option to traceroute that prints the differences between
the probe packet we sent and the packet quoted by the ICMP response. Can be useful for spotting hops that change the packet in-flight or have problems generating correct ICMP responses. MFC after: 3 weeks
Notes
Notes: svn path=/head/; revision=163387
Diffstat (limited to 'contrib')
-rw-r--r--contrib/traceroute/traceroute.820
-rw-r--r--contrib/traceroute/traceroute.c58
2 files changed, 72 insertions, 6 deletions
diff --git a/contrib/traceroute/traceroute.8 b/contrib/traceroute/traceroute.8
index 710ecde72c48..3592c517351d 100644
--- a/contrib/traceroute/traceroute.8
+++ b/contrib/traceroute/traceroute.8
@@ -24,7 +24,7 @@ traceroute \- print the route packets take to network host
.na
.B traceroute
[
-.B \-deFISdnrvx
+.B \-dDeFISdnrvx
] [
.B \-f
.I first_ttl
@@ -112,6 +112,18 @@ Set the "don't fragment" bit.
.B \-d
Enable socket level debugging.
.TP
+.B \-D
+When an ICMP response to our probe datagram is received,
+print the differences between the transmitted packet and
+the packet quoted by the ICMP response.
+A key showing the location of fields within the transmitted packet is printed,
+followed by the original packet in hex,
+followed by the quoted packet in hex.
+Bytes that are unchanged in the quoted packet are shown as underscores.
+Note,
+the IP checksum and the TTL of the quoted packet are not expected to match.
+By default, only one probe per hop is sent with this option.
+.TP
.B \-g
Specify a loose source route gateway (8 maximum).
.TP
@@ -163,7 +175,11 @@ listening on a port in the default range, this option can be used
to pick an unused port range.
.TP
.B \-q
-Set the number of probes per hop (default is 3).
+Set the number of probes per hop (default is 3,
+unless
+.B -D
+is specified,
+when it is 1).
.TP
.B \-r
Bypass the normal routing tables and send directly to a host on an attached
diff --git a/contrib/traceroute/traceroute.c b/contrib/traceroute/traceroute.c
index fd4165a31e8e..d727ccc707ec 100644
--- a/contrib/traceroute/traceroute.c
+++ b/contrib/traceroute/traceroute.c
@@ -316,6 +316,9 @@ u_char packet[512]; /* last inbound (icmp) packet */
struct ip *outip; /* last output ip packet */
u_char *outp; /* last output inner protocol packet */
+struct ip *hip = NULL; /* Quoted IP header */
+int hiplen = 0;
+
/* loose source route gateway list (including room for final destination) */
u_int32_t gwlist[NGATEWAYS + 1];
@@ -337,7 +340,7 @@ char *hostname;
char *device;
static const char devnull[] = "/dev/null";
-int nprobes = 3;
+int nprobes = -1;
int max_ttl;
int first_ttl = 1;
u_short ident;
@@ -354,6 +357,7 @@ int doipcksum = 1; /* calculate ip checksums by default */
#endif
int optlen; /* length of ip options */
int fixedPort = 0; /* Use fixed destination port for TCP and UDP */
+int printdiff = 0; /* Print the difference between sent and quoted */
extern int optind;
extern int opterr;
@@ -380,6 +384,7 @@ int str2val(const char *, const char *, int, int);
void tvsub(struct timeval *, struct timeval *);
void usage(void);
int wait_for_reply(int, struct sockaddr_in *, const struct timeval *);
+void pkt_compare(const u_char *, int, const u_char *, int);
#ifndef HAVE_USLEEP
int usleep(u_int);
#endif
@@ -398,6 +403,7 @@ int icmp_check(const u_char *, int);
/* Descriptor structure for each outgoing protocol we support */
struct outproto {
char *name; /* name of protocol */
+ const char *key; /* An ascii key for the bytes of the header */
u_char num; /* IP protocol number */
u_short hdrlen; /* max size of protocol header */
u_short port; /* default base protocol-specific "port" */
@@ -412,6 +418,7 @@ struct outproto {
struct outproto protos[] = {
{
"udp",
+ "spt dpt len sum",
IPPROTO_UDP,
sizeof(struct udphdr),
32768 + 666,
@@ -420,6 +427,7 @@ struct outproto protos[] = {
},
{
"tcp",
+ "spt dpt seq ack xxflwin sum urp",
IPPROTO_TCP,
sizeof(struct tcphdr),
32768 + 666,
@@ -428,6 +436,7 @@ struct outproto protos[] = {
},
{
"gre",
+ "flg pro len clid",
IPPROTO_GRE,
sizeof(struct grehdr),
GRE_PPTP_PROTO,
@@ -436,6 +445,7 @@ struct outproto protos[] = {
},
{
"icmp",
+ "typ cod sum ",
IPPROTO_ICMP,
sizeof(struct icmp),
0,
@@ -444,6 +454,7 @@ struct outproto protos[] = {
},
{
NULL,
+ NULL,
0,
2 * sizeof(u_short),
0,
@@ -453,6 +464,8 @@ struct outproto protos[] = {
};
struct outproto *proto = &protos[0];
+const char *ip_hdr_key = "vhtslen id off tlprsum srcip dstip opts";
+
int
main(int argc, char **argv)
{
@@ -522,13 +535,17 @@ main(int argc, char **argv)
prog = argv[0];
opterr = 0;
- while ((op = getopt(argc, argv, "edFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF)
+ while ((op = getopt(argc, argv, "edDFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF)
switch (op) {
case 'd':
options |= SO_DEBUG;
break;
+ case 'D':
+ printdiff = 1;
+ break;
+
case 'e':
fixedPort = 1;
break;
@@ -628,6 +645,9 @@ main(int argc, char **argv)
/* Set requested port, if any, else default for this protocol */
port = (requestPort != -1) ? requestPort : proto->port;
+ if (nprobes == -1)
+ nprobes = printdiff ? 1 : 3;
+
if (first_ttl > max_ttl) {
Fprintf(stderr,
"%s: first ttl (%d) may not be greater than max ttl (%d)\n",
@@ -968,6 +988,16 @@ main(int argc, char **argv)
#endif
precis = 3;
Printf(" %.*f ms", precis, T);
+ if (printdiff) {
+ Printf("\n");
+ Printf("%*.*s%s\n",
+ -(outip->ip_hl << 3),
+ outip->ip_hl << 3,
+ ip_hdr_key,
+ proto->key);
+ pkt_compare((void *)outip, packlen,
+ (void *)hip, hiplen);
+ }
if (i == -2) {
#ifndef ARCHAIC
ip = (struct ip *)packet;
@@ -1275,10 +1305,10 @@ packet_ok(register u_char *buf, int cc, register struct sockaddr_in *from,
return -2;
if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
type == ICMP_UNREACH) {
- struct ip *hip;
u_char *inner;
hip = &icp->icmp_ip;
+ hiplen = ((u_char *)icp + cc) - (u_char *)hip;
hlen = hip->ip_hl << 2;
inner = (u_char *)((u_char *)hip + hlen);
if (hlen + 12 <= cc
@@ -1708,13 +1738,33 @@ setproto(char *pname)
}
void
+pkt_compare(const u_char *a, int la, const u_char *b, int lb) {
+ int l;
+ int i;
+
+ for (i = 0; i < la; i++)
+ Printf("%02x", (unsigned int)a[i]);
+ Printf("\n");
+ l = (la <= lb) ? la : lb;
+ for (i = 0; i < l; i++)
+ if (a[i] == b[i])
+ Printf("__");
+ else
+ Printf("%02x", (unsigned int)b[i]);
+ for (; i < lb; i++)
+ Printf("%02x", (unsigned int)b[i]);
+ Printf("\n");
+}
+
+
+void
usage(void)
{
extern char version[];
Fprintf(stderr, "Version %s\n", version);
Fprintf(stderr,
- "Usage: %s [-dFInrSvx] [-g gateway] [-i iface] [-f first_ttl]\n"
+ "Usage: %s [-dDFInrSvx] [-g gateway] [-i iface] [-f first_ttl]\n"
"\t[-m max_ttl] [-p port] [-P proto] [-q nqueries] [-s src_addr]\n"
"\t[-t tos] [-w waittime] [-z pausemsecs] host [packetlen]\n", prog);
exit(1);