Subject: LSRR traceroute
To: None <tech-net@netbsd.org>
From: John Hawkinson <jhawk@panix.com>
List: tech-net
Date: 12/17/1994 20:28:16
Attached are patches adding loose source routing (-g) to
NetBSD's traceroute; this also adds a few miscellaneous
cleanups, a -D option to print out packets before sending
them.
In case anyone is curious, this is different from the standard
traceroute -g as 4.4 no longer supports setsockopt(,,IP_OPTIONS,,)
on raw IP sockets.
--
John Hawkinson
jhawk@panix.com
===================================================================
RCS file: /afs/sipb/user/jhawk/CVS/traceroute/traceroute.8,v
retrieving revision 1.1
diff -c -r1.1 traceroute.8
*** 1.1 1994/12/14 07:54:09
--- traceroute.8 1994/12/18 01:15:04
***************
*** 33,39 ****
.\" SUCH DAMAGE.
.\"
.\" @(#)traceroute.8 8.1 (Berkeley) 6/6/93
! .\" $Id: traceroute.8,v 1.1 1994/12/14 07:54:09 jhawk Exp $
.\"
.Dd June 6, 1993
.Dt TRACEROUTE 8
--- 33,39 ----
.\" SUCH DAMAGE.
.\"
.\" @(#)traceroute.8 8.1 (Berkeley) 6/6/93
! .\" $Id: traceroute.8,v 1.2 1994/12/18 01:15:03 jhawk Exp $
.\"
.Dd June 6, 1993
.Dt TRACEROUTE 8
***************
*** 43,48 ****
--- 43,51 ----
.Nd print the route packets take to network host
.Sh SYNOPSIS
.Nm traceroute
+ .Op Fl d
+ .Op Fl D
+ .Op Fl g Ar addr
.Op Fl m Ar max_ttl
.Op Fl n
.Op Fl p Ar port
***************
*** 74,79 ****
--- 77,93 ----
.Pp
Other options are:
.Bl -tag -width Ds
+ .It Fl d
+ Turns on socket-level debugging.
+ .It Fl D
+ Causes
+ .Nm Traceroute
+ to dump each packet to standard error before sending it.
+ .It Fl g Ar addr
+ Enable the IP LSRR (Loose Source Record Route) option in addition to the
+ TTL tests. This is useful for asking how somebody else, at IP address
+ .Ar addr ,
+ reaches a particular target.
.It Fl m Ar max_ttl
Set the max time-to-live (max number of hops) used in outgoing probe
packets. The default is 30 hops (the same default used for
***************
*** 316,321 ****
--- 330,347 ----
almost all the probes result in some kind of unreachable,
.Nm traceroute
will give up and exit.
+ .Pp
+ .Bd -literal
+ traceroute \-g 10.3.0.5 128.182.0.0
+
+ .Ed
+ will show the path from the Cambridge Mailbridge to PSC while
+ .Bd -literal
+ traceroute \-g 192.5.146.4 \-g 10.3.0.5 35.0.0.0
+
+ .Ed
+ shows how the Cambridge Mailbrige reaches Merit,
+ by using PSC to reach the Mailbridge.
.Pp
This program is intended for use in network testing, measurement
and management.
===================================================================
RCS file: /afs/sipb/user/jhawk/CVS/traceroute/traceroute.c,v
retrieving revision 1.1
diff -c -r1.1 traceroute.c
*** 1.1 1994/12/14 07:54:09
--- traceroute.c 1994/12/18 01:15:06
***************
*** 42,48 ****
#ifndef lint
/*static char sccsid[] = "from: @(#)traceroute.c 8.1 (Berkeley) 6/6/93";*/
! static char *rcsid = "$Id: traceroute.c,v 1.1 1994/12/14 07:54:09 jhawk Exp $";
#endif /* not lint */
/*
--- 42,48 ----
#ifndef lint
/*static char sccsid[] = "from: @(#)traceroute.c 8.1 (Berkeley) 6/6/93";*/
! static char *rcsid = "$Id: traceroute.c,v 1.6 1994/12/18 01:15:05 jhawk Exp $";
#endif /* not lint */
/*
***************
*** 226,235 ****
--- 226,237 ----
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
+ #include <netinet/ip_var.h>
#include <netinet/udp.h>
#include <arpa/inet.h>
+ #include <ctype.h>
#include <netdb.h>
#include <stdio.h>
#include <errno.h>
***************
*** 237,255 ****
#include <string.h>
#include <unistd.h>
! #define MAXPACKET 65535 /* max ip packet size */
! #ifndef MAXHOSTNAMELEN
! #define MAXHOSTNAMELEN 64
! #endif
!
! #ifndef FD_SET
! #define NFDBITS (8*sizeof(fd_set))
! #define FD_SETSIZE NFDBITS
! #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
! #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
! #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
! #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
! #endif
#define Fprintf (void)fprintf
#define Sprintf (void)sprintf
--- 239,245 ----
#include <string.h>
#include <unistd.h>
! #define HEADERSIZE (sizeof(struct ip) + lsrrlen + sizeof(struct udphdr) + sizeof(struct packetdata))
#define Fprintf (void)fprintf
#define Sprintf (void)sprintf
***************
*** 258,276 ****
/*
* format of a (udp) probe packet.
*/
! struct opacket {
! struct ip ip;
! struct udphdr udp;
u_char seq; /* sequence number of this packet */
u_char ttl; /* ttl packet left with */
struct timeval tv; /* time packet left */
};
! u_char packet[512]; /* last inbound (icmp) packet */
! struct opacket *outpacket; /* last output (udp) packet */
int wait_for_reply __P((int, struct sockaddr_in *));
! void send_probe __P((int, int));
double deltaT __P((struct timeval *, struct timeval *));
int packet_ok __P((u_char *, int, struct sockaddr_in *, int));
void print __P((u_char *, int, struct sockaddr_in *));
--- 248,268 ----
/*
* format of a (udp) probe packet.
*/
! struct packetdata {
u_char seq; /* sequence number of this packet */
u_char ttl; /* ttl packet left with */
struct timeval tv; /* time packet left */
};
! #define MAX_LSRR ((MAX_IPOPTLEN-3)/4)
! struct in_addr gateway[MAX_LSRR + 1];
!
! u_char packet[512]; /* last inbound (icmp) packet */
! char *outpacket;
! int lsrrlen = 0;
int wait_for_reply __P((int, struct sockaddr_in *));
! void send_probe __P((int, int, struct sockaddr_in *));
double deltaT __P((struct timeval *, struct timeval *));
int packet_ok __P((u_char *, int, struct sockaddr_in *, int));
void print __P((u_char *, int, struct sockaddr_in *));
***************
*** 282,288 ****
int sndsock; /* send (udp) socket file descriptor */
struct timezone tz; /* leftover */
- struct sockaddr whereto; /* Who to try to reach */
int datalen; /* How much data */
char *source = 0;
--- 274,279 ----
***************
*** 296,301 ****
--- 287,294 ----
int verbose;
int waittime = 5; /* time to wait for response (in seconds) */
int nflag; /* print addresses numerically */
+ int dump;
+
int
main(argc, argv)
***************
*** 306,327 ****
extern int optind;
struct hostent *hp;
struct protoent *pe;
! struct sockaddr_in from, *to;
! int ch, i, on, probe, seq, tos, ttl;
on = 1;
! seq = tos = 0;
! to = (struct sockaddr_in *)&whereto;
! while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
switch(ch) {
case 'd':
options |= SO_DEBUG;
break;
case 'm':
max_ttl = atoi(optarg);
! if (max_ttl <= 1) {
Fprintf(stderr,
! "traceroute: max ttl must be >1.\n");
exit(1);
}
break;
--- 299,346 ----
extern int optind;
struct hostent *hp;
struct protoent *pe;
! struct sockaddr_in from, to;
!
! int ch, i, lsrr, on, probe, seq, tos, ttl;
! u_long gw; /* LSRR gateway host */
! struct ip *ip;
on = 1;
! lsrr = seq = tos = 0;
! while ((ch = getopt(argc, argv, "dDg:m:np:q:rs:t:w:v")) != EOF)
switch(ch) {
case 'd':
options |= SO_DEBUG;
break;
+ case 'D':
+ dump = 1;
+ break;
+ case 'g':
+ if (lsrr > MAX_LSRR) {
+ Fprintf(stderr, "too many gateways; only %d allowed\n",
+ MAX_LSRR);
+ exit(1);
+ }
+ gw = inet_addr(optarg);
+ if (gw == -1) {
+ hp = gethostbyname(optarg);
+ if (hp == 0) {
+ Fprintf(stderr, "Unknown host %s\n", optarg);
+ exit(1);
+ }
+ bcopy(hp->h_addr, &gw, 4);
+ }
+ gateway[lsrr].s_addr = gw;
+ if (lsrr++ == 0)
+ lsrrlen = 4;
+ lsrrlen += 4;
+ break;
case 'm':
max_ttl = atoi(optarg);
! if (max_ttl < 1 || max_ttl > MAXTTL) {
Fprintf(stderr,
! "traceroute: max ttl must be 1 to %d\n",
! MAXTTL);
exit(1);
}
break;
***************
*** 332,338 ****
port = atoi(optarg);
if (port < 1) {
Fprintf(stderr,
! "traceroute: port must be >0.\n");
exit(1);
}
break;
--- 351,357 ----
port = atoi(optarg);
if (port < 1) {
Fprintf(stderr,
! "traceroute: port must be > 0.\n");
exit(1);
}
break;
***************
*** 340,346 ****
nprobes = atoi(optarg);
if (nprobes < 1) {
Fprintf(stderr,
! "traceroute: nprobes must be >0.\n");
exit(1);
}
break;
--- 359,365 ----
nprobes = atoi(optarg);
if (nprobes < 1) {
Fprintf(stderr,
! "traceroute: nprobes must be > 0.\n");
exit(1);
}
break;
***************
*** 369,375 ****
waittime = atoi(optarg);
if (waittime <= 1) {
Fprintf(stderr,
! "traceroute: wait must be >1 sec.\n");
exit(1);
}
break;
--- 388,394 ----
waittime = atoi(optarg);
if (waittime <= 1) {
Fprintf(stderr,
! "traceroute: wait must be > 1 sec.\n");
exit(1);
}
break;
***************
*** 384,425 ****
setlinebuf (stdout);
! (void) bzero((char *)&whereto, sizeof(struct sockaddr));
! to->sin_family = AF_INET;
! to->sin_addr.s_addr = inet_addr(*argv);
! if (to->sin_addr.s_addr != -1)
hostname = *argv;
else {
hp = gethostbyname(*argv);
! if (hp) {
! to->sin_family = hp->h_addrtype;
! bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
! hostname = hp->h_name;
! } else {
(void)fprintf(stderr,
"traceroute: unknown host %s\n", *argv);
exit(1);
}
}
if (*++argv)
datalen = atoi(*argv);
! if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) {
Fprintf(stderr,
"traceroute: packet size must be 0 <= s < %ld.\n",
! MAXPACKET - sizeof(struct opacket));
exit(1);
}
! datalen += sizeof(struct opacket);
! outpacket = (struct opacket *)malloc((unsigned)datalen);
! if (! outpacket) {
perror("traceroute: malloc");
exit(1);
}
! (void) bzero((char *)outpacket, datalen);
! outpacket->ip.ip_dst = to->sin_addr;
! outpacket->ip.ip_tos = tos;
! outpacket->ip.ip_v = IPVERSION;
! outpacket->ip.ip_id = 0;
ident = (getpid() & 0xffff) | 0x8000;
--- 403,460 ----
setlinebuf (stdout);
! (void) bzero((char *)&to, sizeof(struct sockaddr));
! to.sin_family = AF_INET;
! to.sin_addr.s_addr = inet_addr(*argv);
! if (to.sin_addr.s_addr != -1)
hostname = *argv;
else {
hp = gethostbyname(*argv);
! if (hp == 0) {
(void)fprintf(stderr,
"traceroute: unknown host %s\n", *argv);
exit(1);
}
+ to.sin_family = hp->h_addrtype;
+ bcopy(hp->h_addr, (caddr_t)&to.sin_addr, hp->h_length);
+ hostname = hp->h_name;
}
if (*++argv)
datalen = atoi(*argv);
! if (datalen < 0 || datalen >= IP_MAXPACKET - HEADERSIZE) {
Fprintf(stderr,
"traceroute: packet size must be 0 <= s < %ld.\n",
! IP_MAXPACKET - HEADERSIZE);
exit(1);
}
! datalen += HEADERSIZE;
! outpacket = (char *)malloc(datalen);
! if (outpacket == 0) {
perror("traceroute: malloc");
exit(1);
}
!
! (void) bzero(outpacket, datalen);
! ip = (struct ip *)outpacket;
! if (lsrr != 0) {
! u_char *p;
! p = (u_char *)(ip + 1);
! *p++ = IPOPT_NOP;
! *p++ = IPOPT_LSRR;
! *p++ = 3 + lsrr * 4;
! *p++ = IPOPT_MINOFF;
! gateway[lsrr] = to.sin_addr;
! for (i = 1; i <= lsrr; i++)
! *((struct in_addr *)p)++ = gateway[i];
! ip->ip_dst = gateway[0];
! } else
! ip->ip_dst = to.sin_addr;
! ip->ip_off = 0;
! ip->ip_hl = (sizeof(struct ip) + lsrrlen) >> 2;
! ip->ip_p = IPPROTO_UDP;
! ip->ip_v = IPVERSION;
! ip->ip_tos = tos;
! ip->ip_id = 0;
ident = (getpid() & 0xffff) | 0x8000;
***************
*** 442,447 ****
--- 477,483 ----
perror("traceroute: raw socket");
exit(5);
}
+
#ifdef SO_SNDBUF
if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
sizeof(datalen)) < 0) {
***************
*** 471,477 ****
Printf("traceroute: unknown host %s\n", source);
exit(1);
}
! outpacket->ip.ip_src = from.sin_addr;
#ifndef IP_HDRINCL
if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) {
perror ("traceroute: bind:");
--- 507,513 ----
Printf("traceroute: unknown host %s\n", source);
exit(1);
}
! ip->ip_src = from.sin_addr;
#ifndef IP_HDRINCL
if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) {
perror ("traceroute: bind:");
***************
*** 481,487 ****
}
Fprintf(stderr, "traceroute to %s (%s)", hostname,
! inet_ntoa(to->sin_addr));
if (source)
Fprintf(stderr, " from %s", source);
Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
--- 517,523 ----
}
Fprintf(stderr, "traceroute to %s (%s)", hostname,
! inet_ntoa(to.sin_addr));
if (source)
Fprintf(stderr, " from %s", source);
Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
***************
*** 497,506 ****
int cc;
struct timeval t1, t2;
struct timezone tz;
- struct ip *ip;
(void) gettimeofday(&t1, &tz);
! send_probe(++seq, ttl);
while (cc = wait_for_reply(s, &from)) {
(void) gettimeofday(&t2, &tz);
if ((i = packet_ok(packet, cc, &from, seq))) {
--- 533,541 ----
int cc;
struct timeval t1, t2;
struct timezone tz;
(void) gettimeofday(&t1, &tz);
! send_probe(++seq, ttl, &to);
while (cc = wait_for_reply(s, &from)) {
(void) gettimeofday(&t2, &tz);
if ((i = packet_ok(packet, cc, &from, seq))) {
***************
*** 547,553 ****
(void) fflush(stdout);
}
putchar('\n');
! if (got_there || unreachable >= nprobes-1)
exit(0);
}
}
--- 582,588 ----
(void) fflush(stdout);
}
putchar('\n');
! if (got_there || unreachable >= nprobes)
exit(0);
}
}
***************
*** 573,607 ****
return(cc);
}
void
! send_probe(seq, ttl)
int seq, ttl;
{
! struct opacket *op = outpacket;
! struct ip *ip = &op->ip;
! struct udphdr *up = &op->udp;
int i;
- ip->ip_off = 0;
- ip->ip_hl = sizeof(*ip) >> 2;
- ip->ip_p = IPPROTO_UDP;
ip->ip_len = datalen;
ip->ip_ttl = ttl;
- ip->ip_v = IPVERSION;
ip->ip_id = htons(ident+seq);
up->uh_sport = htons(ident);
up->uh_dport = htons(port+seq);
! up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip)));
up->uh_sum = 0;
op->seq = seq;
op->ttl = ttl;
(void) gettimeofday(&op->tv, &tz);
! i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
! sizeof(struct sockaddr));
if (i < 0 || i != datalen) {
if (i<0)
perror("sendto");
--- 608,658 ----
return(cc);
}
+ void
+ dump_packet()
+ {
+ u_char *p;
+ int i;
+
+ Fprintf(stderr,"packet data:");
+ for (p = outpacket, i = 0; i < datalen; i++) {
+ if ((i % 24) == 0)
+ Fprintf(stderr,"\n");
+ Fprintf(stderr," %02x", *p++);
+ }
+ Fprintf(stderr,"\n");
+ }
void
! send_probe(seq, ttl, to)
int seq, ttl;
+ struct sockaddr_in *to;
{
! struct ip *ip = (struct ip *)outpacket;
! u_char *p = (u_char *)(ip + 1);
! struct udphdr *up = (struct udphdr *)(p + lsrrlen);
! struct packetdata *op = (struct packetdata *)(up + 1);
! /* u_char *opts = &op->ipoptions; Do we need this? */
int i;
ip->ip_len = datalen;
ip->ip_ttl = ttl;
ip->ip_id = htons(ident+seq);
up->uh_sport = htons(ident);
up->uh_dport = htons(port+seq);
! up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip) - lsrrlen));
up->uh_sum = 0;
op->seq = seq;
op->ttl = ttl;
(void) gettimeofday(&op->tv, &tz);
! if (dump)
! dump_packet();
!
! i = sendto(sndsock, outpacket, datalen, 0, (struct sockaddr *)to,
! sizeof(struct sockaddr_in));
if (i < 0 || i != datalen) {
if (i<0)
perror("sendto");
***************
*** 830,836 ****
usage()
{
(void)fprintf(stderr,
! "usage: traceroute [-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n\t\
! [-s src_addr] [-t tos] [-w wait] host [data size]\n");
exit(1);
}
--- 881,887 ----
usage()
{
(void)fprintf(stderr,
! "usage: traceroute [-dDnrv] [-m max_ttl] [-p port#] [-q nqueries]\n\t\
! [-s src_addr] [-t tos] [-w wait] [-g gateway] host [data size]\n");
exit(1);
}