summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorarchie <archie@FreeBSD.org>1999-05-06 03:23:24 +0000
committerarchie <archie@FreeBSD.org>1999-05-06 03:23:24 +0000
commit78c2183cb646fef06657bbcf5849e433600ce2e3 (patch)
treeb73667c2ac1116ec517d50021e8d7012a2b19edf
parent254c5bc5a20a0ae065603b34619a9979d1029023 (diff)
downloadFreeBSD-src-78c2183cb646fef06657bbcf5849e433600ce2e3.zip
FreeBSD-src-78c2183cb646fef06657bbcf5849e433600ce2e3.tar.gz
Add the capability for traceroute(8) to send packets of any IP protocol
instead of just UDP; an alternate protocol is specified by '-P proto'. This is useful for finding routers that are blocking packets based on IP protocol. New handlers can be added fairly easily to do protocol- specific things.
-rw-r--r--contrib/traceroute/traceroute.834
-rw-r--r--contrib/traceroute/traceroute.c247
2 files changed, 244 insertions, 37 deletions
diff --git a/contrib/traceroute/traceroute.8 b/contrib/traceroute/traceroute.8
index d4f1bc2..26e11b6 100644
--- a/contrib/traceroute/traceroute.8
+++ b/contrib/traceroute/traceroute.8
@@ -13,7 +13,7 @@
.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
-.\" $Header: /home/ncvs/src/contrib/traceroute/traceroute.8,v 1.2 1996/10/08 02:44:23 sef Exp $
+.\" $Header: /home/ncvs/src/contrib/traceroute/traceroute.8,v 1.3 1998/01/09 18:46:53 steve Exp $
.\"
.TH TRACEROUTE 8 "27 September 1996"
.UC 6
@@ -35,24 +35,29 @@ max_ttl
.br
.ti +8
[
+.B \-P
+.I proto
+] [
.B \-p
.I port
] [
.B \-q
.I nqueries
-] [
-.B \-s
-.I src_addr
]
.br
.ti +8
[
+.B \-s
+.I src_addr
+] [
.B \-t
.I tos
] [
.B \-w
.I waittime
]
+.br
+.ti +8
.I host
[
.I packetlen
@@ -91,8 +96,18 @@ Print hop addresses numerically rather than symbolically and numerically
(saves a nameserver address-to-name lookup for each gateway found on the
path).
.TP
+.B \-P
+Send packets of specified IP protocol. The currently supported protocols
+are: UDP, TCP and GRE. Other protocols may also be specified (either by
+name or by number), though
+.I traceroute
+does not implement any special knowledge of their packet formats. This
+option is useful for determining which router along a path may be
+blocking packets based on IP protocol number. But see BUGS below.
+.TP
.B \-p
-Set the base UDP port number used in probes (default is 33434).
+Protocol specific. For UDP and TCP, sets
+the base port number used in probes (default is 33434).
Traceroute hopes that nothing is listening on UDP ports
.I base
to
@@ -298,4 +313,13 @@ The current version is available via anonymous ftp:
.I ftp://ftp.ee.lbl.gov/traceroute.tar.Z
.RE
.SH BUGS
+When using protocols other than UDP, functionality is reduced.
+In particular, the last packet will often appear to be lost, because
+even though it reaches the destination host, there's no way to know
+that because no ICMP message is sent back.
+In the TCP case,
+.I traceroute
+should listen for a RST from the destination host (or an intermediate
+router that's filtering packets), but this is not implemented yet.
+.PP
Please send bug reports to traceroute@ee.lbl.gov.
diff --git a/contrib/traceroute/traceroute.c b/contrib/traceroute/traceroute.c
index 9f235a5..2a6dd51 100644
--- a/contrib/traceroute/traceroute.c
+++ b/contrib/traceroute/traceroute.c
@@ -24,7 +24,7 @@ static const char copyright[] =
"@(#) Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996\n\
The Regents of the University of California. All rights reserved.\n";
static const char rcsid[] =
- "@(#)$Header: /home/ncvs/src/contrib/traceroute/traceroute.c,v 1.7 1999/02/15 08:11:44 des Exp $ (LBL)";
+ "@(#)$Header: /home/ncvs/src/contrib/traceroute/traceroute.c,v 1.8 1999/02/16 14:19:50 des Exp $ (LBL)";
#endif
/*
@@ -213,6 +213,7 @@ static const char rcsid[] =
#include <netinet/ip_var.h>
#include <netinet/ip_icmp.h>
#include <netinet/udp.h>
+#include <netinet/tcp.h>
#include <arpa/inet.h>
@@ -243,6 +244,20 @@ static const char rcsid[] =
#define Fprintf (void)fprintf
#define Printf (void)printf
+/* What a GRE packet header looks like */
+struct grehdr {
+ u_int16_t flags;
+ u_int16_t proto;
+ u_int16_t length; /* PPTP version of these fields */
+ u_int16_t callId;
+};
+#ifndef IPPROTO_GRE
+#define IPPROTO_GRE 47
+#endif
+
+/* For GRE, we prepare what looks like a PPTP packet */
+#define GRE_PPTP_PROTO 0x880b
+
/* Data section of the probe packet */
struct outdata {
u_char seq; /* sequence number of this packet */
@@ -250,11 +265,22 @@ struct outdata {
struct timeval tv; /* time packet left */
};
+/* Descriptor structure for each outgoing protocol we support */
+struct outproto {
+ char *name; /* name of protocol */
+ u_char num; /* IP protocol number */
+ u_short hdrlen; /* max size of protocol header */
+ u_short port; /* default base protocol-specific "port" */
+ void (*prepare)(struct outdata *);
+ /* finish preparing an outgoing packet */
+ int (*check)(const u_char *, int);
+ /* check an incoming packet */
+};
+
u_char packet[512]; /* last inbound (icmp) packet */
-struct ip *outip; /* last output (udp) packet */
-struct udphdr *outudp; /* last output (udp) packet */
-struct outdata *outdata; /* last output (udp) packet */
+struct ip *outip; /* last output ip packet */
+u_char *outprot; /* last output inner protocol packet */
/* loose source route gateway list (including room for final destination) */
u_int32_t gwlist[NGATEWAYS + 1];
@@ -264,6 +290,7 @@ int sndsock; /* send (udp) socket file descriptor */
struct sockaddr whereto; /* Who to try to reach */
int packlen; /* total length of packet */
+int protlen; /* length of protocol part of packet */
int maxpacket = 32 * 1024; /* max ip packet size */
char *prog;
@@ -273,7 +300,7 @@ char *hostname;
int nprobes = 3;
int max_ttl = 30;
u_short ident;
-u_short port = 32768 + 666; /* start udp dest port # for probe packets */
+u_short port; /* protocol specific base "port" */
int options; /* socket options */
int verbose;
@@ -294,11 +321,58 @@ void print(u_char *, int, struct sockaddr_in *);
char *getaddr(u_int32_t *, char *);
char *getsin(struct sockaddr_in *, char *);
char *savestr(const char *);
-void send_probe(int, int, struct timeval *);
+void send_probe(int, int);
void tvsub(struct timeval *, struct timeval *);
__dead void usage(void);
int wait_for_reply(int, struct sockaddr_in *, struct timeval *);
+void udp_prep(struct outdata *);
+int udp_check(const u_char *, int);
+void tcp_prep(struct outdata *);
+int tcp_check(const u_char *, int);
+void gre_prep(struct outdata *);
+int gre_check(const u_char *, int);
+void gen_prep(struct outdata *);
+int gen_check(const u_char *, int);
+
+/* List of supported protocols. The first one is the default. The last
+ one is the handler for generic protocols not explicitly listed. */
+struct outproto protos[] = {
+ {
+ "udp",
+ IPPROTO_UDP,
+ sizeof(struct udphdr),
+ 32768 + 666,
+ udp_prep,
+ udp_check
+ },
+ {
+ "tcp",
+ IPPROTO_TCP,
+ sizeof(struct tcphdr),
+ 32768 + 666,
+ tcp_prep,
+ tcp_check
+ },
+ {
+ "gre",
+ IPPROTO_GRE,
+ sizeof(struct grehdr),
+ GRE_PPTP_PROTO,
+ gre_prep,
+ gre_check
+ },
+ {
+ NULL,
+ 0,
+ 2 * sizeof(u_short),
+ 0,
+ gen_prep,
+ gen_check
+ },
+};
+struct outproto *proto = &protos[0];
+
int
main(int argc, char **argv)
{
@@ -338,7 +412,7 @@ main(int argc, char **argv)
prog = argv[0];
opterr = 0;
- while ((op = getopt(argc, argv, "Sdnrvg:m:p:q:s:t:w:")) != EOF)
+ while ((op = getopt(argc, argv, "Sdnrvg:m:P:p:q:s:t:w:")) != EOF)
switch (op) {
case 'S':
@@ -372,6 +446,36 @@ main(int argc, char **argv)
++nflag;
break;
+ case 'P':
+ for (i = 0; protos[i].name != NULL; i++) {
+ if (strcasecmp(protos[i].name, optarg) == 0) {
+ proto = &protos[i];
+ break;
+ }
+ }
+ if (protos[i].name == NULL) { /* generic handler */
+ struct protoent *pe;
+ u_long pnum;
+ char *eptr;
+
+ /* Determine the IP protocol number */
+ if ((pe = getprotobyname(optarg)) != NULL)
+ pnum = pe->p_proto;
+ else {
+ pnum = strtoul(optarg, &eptr, 10);
+ if (pnum > 0xff
+ || *optarg == '\0'
+ || *eptr != '\0') {
+ Fprintf(stderr, "%s: unknown "
+ "protocol \"%s\"\n",
+ prog, optarg);
+ exit(1);
+ }
+ }
+ proto->num = pnum;
+ }
+ break;
+
case 'p':
port = atoi(optarg);
if (port <= 0) {
@@ -451,7 +555,7 @@ main(int argc, char **argv)
if (lsrr > 0)
optlen = (lsrr + 1) * sizeof(gwlist[0]);
- i = sizeof(*outip) + sizeof(*outudp) + sizeof(*outdata) + optlen;
+ i = sizeof(*outip) + proto->hdrlen + sizeof(struct outdata) + optlen;
if (packlen == 0)
packlen = i; /* minimum sized packet */
else if (i > packlen || packlen > maxpacket) {
@@ -459,6 +563,7 @@ main(int argc, char **argv)
prog, i, maxpacket);
exit(1);
}
+ protlen = packlen - sizeof(*outip) - optlen;
outip = (struct ip *)malloc((unsigned)packlen);
if (outip == NULL) {
@@ -474,14 +579,14 @@ main(int argc, char **argv)
#else
outip->ip_len = packlen;
#endif
- outip->ip_p = IPPROTO_UDP;
- outudp = (struct udphdr *)(outip + 1);
+ outip->ip_p = proto->num;
+ outprot = (u_char *)(outip + 1);
#ifdef HAVE_RAW_OPTIONS
if (lsrr > 0) {
register u_char *optlist;
- optlist = (u_char *)outudp;
- (u_char *)outudp += optlen;
+ optlist = (u_char *)outprot;
+ (u_char *)outprot += optlen;
/* final hop */
gwlist[lsrr] = to->sin_addr.s_addr;
@@ -501,13 +606,9 @@ main(int argc, char **argv)
#endif
outip->ip_dst = to->sin_addr;
- outip->ip_hl = ((u_char *)outudp - (u_char *)outip) >> 2;
+ outip->ip_hl = ((u_char *)outprot - (u_char *)outip) >> 2;
ident = (getpid() & 0xffff) | 0x8000;
- outudp->uh_sport = htons(ident);
- outudp->uh_ulen = htons((u_short)(packlen - (sizeof(*outip) + optlen)));
-
- outdata = (struct outdata *)(outudp + 1);
if (pe == NULL) {
Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
@@ -616,9 +717,21 @@ main(int argc, char **argv)
struct timeval t1, t2;
struct timezone tz;
register struct ip *ip;
+ struct outdata outdata;
+
+ /* Prepare outgoing data */
+ outdata.seq = ++seq;
+ outdata.ttl = ttl;
+ /* Avoid alignment problems by copying bytewise: */
(void)gettimeofday(&t1, &tz);
- send_probe(++seq, ttl, &t1);
+ memcpy(&outdata.tv, &t1, sizeof(outdata.tv));
+
+ /* Finalize and send packet */
+ (*proto->prepare)(&outdata);
+ send_probe(seq, ttl);
+
+ /* Wait for a reply */
while ((cc = wait_for_reply(s, &from, &t1)) != 0) {
double T;
int precis;
@@ -753,21 +866,13 @@ wait_for_reply(register int sock, register struct sockaddr_in *fromp,
}
void
-send_probe(register int seq, register int ttl, register struct timeval *tp)
+send_probe(int seq, int ttl)
{
register int i;
outip->ip_ttl = ttl;
outip->ip_id = htons(ident + seq);
- outudp->uh_dport = htons(port + seq);
-
- outdata->seq = seq;
- outdata->ttl = ttl;
-
- /* Avoid alignment problems by copying bytewise: */
- memcpy(&outdata->tv, tp, sizeof(outdata->tv));
-
i = sendto(sndsock, (char *)outip, packlen, 0, &whereto,
sizeof(whereto));
if (i < 0 || i != packlen) {
@@ -838,14 +943,14 @@ packet_ok(register u_char *buf, int cc, register struct sockaddr_in *from,
if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
type == ICMP_UNREACH) {
struct ip *hip;
- struct udphdr *up;
+ u_char *inner;
hip = &icp->icmp_ip;
hlen = hip->ip_hl << 2;
- up = (struct udphdr *)((u_char *)hip + hlen);
- if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
- up->uh_sport == htons(ident) &&
- up->uh_dport == htons(port + seq))
+ inner = (u_char *)((u_char *)hip + hlen);
+ if (hlen + 12 <= cc
+ && hip->ip_p == proto->num
+ && (*proto->check)(inner, seq))
return (type == ICMP_TIMXCEED ? -1 : code + 1);
}
#ifndef ARCHAIC
@@ -863,6 +968,84 @@ packet_ok(register u_char *buf, int cc, register struct sockaddr_in *from,
return(0);
}
+void
+udp_prep(struct outdata *outdata)
+{
+ struct udphdr *const udp = (struct udphdr *) outprot;
+
+ udp->uh_sport = htons(ident);
+ udp->uh_dport = htons(port + outdata->seq);
+ udp->uh_ulen = htons((u_short)protlen);
+}
+
+int
+udp_check(const u_char *data, int seq)
+{
+ struct udphdr *const udp = (struct udphdr *) data;
+
+ return (ntohs(udp->uh_sport) == ident
+ && ntohs(udp->uh_dport) == port + seq);
+}
+
+void
+tcp_prep(struct outdata *outdata)
+{
+ struct tcphdr *const tcp = (struct tcphdr *) outprot;
+
+ tcp->th_sport = htons(ident);
+ tcp->th_dport = htons(port + outdata->seq);
+ tcp->th_seq = (tcp->th_sport << 16) | tcp->th_dport;
+ tcp->th_ack = 0;
+ tcp->th_off = 5;
+ tcp->th_flags = TH_SYN;
+}
+
+int
+tcp_check(const u_char *data, int seq)
+{
+ struct tcphdr *const tcp = (struct tcphdr *) data;
+
+ return (ntohs(tcp->th_sport) == ident
+ && ntohs(tcp->th_dport) == port + seq);
+}
+
+void
+gre_prep(struct outdata *outdata)
+{
+ struct grehdr *const gre = (struct grehdr *) outprot;
+
+ gre->flags = htons(0x2001);
+ gre->proto = htons(port);
+ gre->length = 0;
+ gre->callId = htons(ident + outdata->seq);
+}
+
+int
+gre_check(const u_char *data, int seq)
+{
+ struct grehdr *const gre = (struct grehdr *) data;
+
+ return(ntohs(gre->proto) == port
+ && ntohs(gre->callId) == ident + seq);
+}
+
+void
+gen_prep(struct outdata *outdata)
+{
+ u_int16_t *const ptr;
+
+ ptr[0] = htons(ident);
+ ptr[1] = htons(port + outdata->seq);
+}
+
+int
+gen_check(const u_char *data, int seq)
+{
+ u_int16_t *const ptr = (u_int16_t *) data;
+
+ return(ntohs(ptr[0]) == ident
+ && ntohs(ptr[1]) == port + seq);
+}
void
print(register u_char *buf, register int cc, register struct sockaddr_in *from)
OpenPOWER on IntegriCloud