Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 23 Sep 2005 10:51:25 -0700
From:      "Crist J. Clark" <cristjc@comcast.net>
To:        net@freebsd.org
Subject:   Fixed Dest Port for traceroute(8)
Message-ID:  <20050923175125.GA69254@goku.cjclark.org>

next in thread | raw e-mail | index | archive | help
Gee. It would be nice if one could fix the outgoing port for
UDP and TCP traceroutes. Sometimes firewalls, load balancers,
and various other systems treat packets differently depending
on the transport layer destination port. The current traceroute
implementation allows one to specify a starting port, but
increments the port with each packet sent out. It doesn't do
this without reason. The value is essentially a sequence number
that is used to identify out-of-order responses, but this
screws up our ability to traceroute a specific port.

Also, traceroute just needs more options. It's closing on
ping(8).

I have added a '-e' option. A firewall "evasion," fixed-port
option. For TCP and UDP scans, the destination port is not
changed. Doing this in TCP is pretty straightforward. The
sequence number field was already being loaded with the
source port (which in turn is the PID) and destination port.
I stopped incrementing the destination port, but continiued
to increment the dest port part of the sequence number. I
added the sequence number to the out-of-order check.

For UDP, that approach won't work. There isn't much space
available in the header to store a counter, so I switched the
conter to the source port rather than destination. I thought
about abusing the UDP checksum. But that has the side effect
that the destination will drop our last packet rather than
return a port unreachable and has the potential to confuse
NATing devices and other nastiness (although we somehow got
away without TCP checksums at all for a long time). The counter
is only switched when the fixed port option is given.

Anyone mind if I see if my commit bit still works and merge
this in?


Index: traceroute.8
===================================================================
RCS file: /ncvs/freebsd/src/contrib/traceroute/traceroute.8,v
retrieving revision 1.11
diff -u -r1.11 traceroute.8
--- traceroute.8	12 Apr 2005 15:16:32 -0000	1.11
+++ traceroute.8	23 Sep 2005 17:47:12 -0000
@@ -24,7 +24,7 @@
 .na
 .B traceroute
 [
-.B \-dFISdnrvx
+.B \-deFISdnrvx
 ] [
 .B \-f
 .I first_ttl
@@ -98,6 +98,11 @@
 .PP
 Other options are:
 .TP
+.B \-e
+Firewall evasion mode.
+Use fixed destination ports for UDP and TCP probes.
+The destination port does NOT increment with each packet sent.
+.TP
 .B \-f
 Set the initial time-to-live used in the first outgoing probe packet.
 .TP
Index: traceroute.c
===================================================================
RCS file: /ncvs/freebsd/src/contrib/traceroute/traceroute.c,v
retrieving revision 1.27
diff -u -r1.27 traceroute.c
--- traceroute.c	26 Aug 2005 18:08:24 -0000	1.27
+++ traceroute.c	23 Sep 2005 17:47:45 -0000
@@ -353,6 +353,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 */
 
 extern int optind;
 extern int opterr;
@@ -521,13 +522,17 @@
 		prog = argv[0];
 
 	opterr = 0;
-	while ((op = getopt(argc, argv, "dFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF)
+	while ((op = getopt(argc, argv, "edFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF)
 		switch (op) {
 
 		case 'd':
 			options |= SO_DEBUG;
 			break;
 
+		case 'e':
+			fixedPort = 1;
+			break;
+
 		case 'f':
 		case 'M':	/* FreeBSD compat. */
 			first_ttl = str2val(optarg, "first ttl", 1, 255);
@@ -1289,8 +1294,8 @@
 {
 	struct udphdr *const outudp = (struct udphdr *) outp;
 
-	outudp->uh_sport = htons(ident);
-	outudp->uh_dport = htons(port + outdata->seq);
+	outudp->uh_sport = htons(ident + (fixedPort ? outdata->seq : 0));
+	outudp->uh_dport = htons(port + (fixedPort ? 0 : outdata->seq));
 	outudp->uh_ulen = htons((u_short)protlen);
 	outudp->uh_sum = 0;
 	if (doipcksum) {
@@ -1306,8 +1311,8 @@
 {
 	struct udphdr *const udp = (struct udphdr *) data;
 
-	return (ntohs(udp->uh_sport) == ident
-	    && ntohs(udp->uh_dport) == port + seq);
+	return (ntohs(udp->uh_sport) == ident + (fixedPort ? seq : 0) &&
+	    ntohs(udp->uh_dport) == port + (fixedPort ? 0 : seq));
 }
 
 void
@@ -1316,8 +1321,9 @@
 	struct tcphdr *const tcp = (struct tcphdr *) outp;
 
 	tcp->th_sport = htons(ident);
-	tcp->th_dport = htons(port + outdata->seq);
-	tcp->th_seq = (tcp->th_sport << 16) | tcp->th_dport;
+	tcp->th_dport = htons(port + (fixedPort ? 0 : outdata->seq));
+	tcp->th_seq = (tcp->th_sport << 16) | (tcp->th_dport +
+	    (fixedPort ? outdata->seq : 0));
 	tcp->th_ack = 0;
 	tcp->th_off = 5;
 	tcp->th_flags = TH_SYN;
@@ -1335,7 +1341,8 @@
 	struct tcphdr *const tcp = (struct tcphdr *) data;
 
 	return (ntohs(tcp->th_sport) == ident
-	    && ntohs(tcp->th_dport) == port + seq);
+	    && ntohs(tcp->th_dport) == port + (fixedPort ? 0 : seq))
+	    && tcp->th_seq == (ident << 16) | (port + seq);
 }
 
 void
-- 
Crist J. Clark                     |     cjclark@alum.mit.edu



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20050923175125.GA69254>