Traceroute Bug
This document investigates
the peculiar packet structure of the Linux traceroute
utility.
Background
For these tests, I was
using Redhat Linux version 7.2*. The network was two
machines, one on either side of a Cisco 2621. The inside machine used static NATing, and the IP arrangement was as illustrated in the
diagram below.
The router had no rules to
restrict traffic in either direction.
The Windows2k machine had
UDP port 135 open and listening.
There were no previous
connections established.
The NAT translation table
on the router showed only the static NAT:
Outside Global:
216.249.144.222 to Inside Local: 192.168.1.1
Test 1
#traceroute
216.249.144.222 –p 134 -n
The –p 134 was to force
the traceroute routine to use port 135 in its probe.
A portion of the traffic
generated is shown below:
Listing 1:
1 IP-216.249.144.221 IP-216.249.144.222 IP-135 64 IP
UDP
2 IP-216.249.144.225 IP-216.249.144.221 74 ICMP DUnr
3 IP-216.249.144.221 IP-216.249.144.222 IP-136 64 IP
UDP
4 IP-216.249.144.225 IP-216.249.144.221 74 ICMP DUnr
From this we can see that traceroute has send packets to two ports – 135 and 136. In
both cases the router responded with
a Port Unreachable. At first it might appear that the router is responding on behalf of the inside machine. However,
traffic collected on the inside network shows no traffic between router and the
target system.
Test 2
#nmap
–sU 216.249.144.222 –p 135 –n –P0
In this test, I used nmap to generate a similar UDP packet, also to port 135. Below
is the listing showing the packets captured:
Listing 2:
12 IP-216.249.144.221 IP-216.249.144.222 IP-135
64 IP
UDP
13 IP-216.249.144.222 IP-216.249.144.221 IP-54146
130 IP UDP
In this capture we can see
that the end machine (.222) has responded with a UDP packet containing data.
Obviously the packet has gone through the router this time.
This leads one to question
why the UDP packet from the nmap test went through
the router, while the packet from the traceroute did
not. So, let’s open each of these and investigate:
Packet 1 from Listing 1:
UDP Packet from traceroute:
Ethernet Header
Destination:
Source:
Protocol
Type:0x0800 IP
IP Header - Internet
Protocol Datagram
Version: 4
Header
Length: 5 (20 bytes)
Type
of Service: %00000000
Precedence:
Routine, Normal Delay,
Total
Length: 38
Identifier: 19302
Fragmentation
Flags: %000 May Fragment Last Fragment
Fragment
Offset: 0 (0 bytes)
Time
To Live:
1
Protocol: 17 UDP
Header
Checksum: 0x9AB2
Source
IP Address: 216.249.144.221
Dest. IP Address: 216.249.144.222
No
IP Options
UDP - User Datagram Protocol
Length: 18
Checksum: 0xBC8F
UDP
Data Area:
.. 01 01
Extra bytes (Padding):
From this we see an
immediate problem. The UDP header length is 18 bytes – which is illegal since
all headers must have a long-word boundary (i.e. a length that is evenly
divisible by 4). Let’s look at the nmap packet now,
just for verification:
Listing 2, Packet 12: UDP
Packet from nmap
Ethernet Header
Destination:
Source:
Protocol
Type:0x0800 IP
IP Header - Internet
Protocol Datagram
Version: 4
Header
Length: 5 (20 bytes)
Type
of Service: %00000000
Precedence:
Routine, Normal Delay,
Total
Length: 28
Identifier: 39350
Fragmentation
Flags: %000 May Fragment Last Fragment
Fragment
Offset: 0 (0 bytes)
Time
To Live:
58
Protocol:
17 UDP
Header
Checksum: 0x136C
Source
IP Address: 216.249.144.221
Dest. IP Address: 216.249.144.222
No
IP Options
UDP - User Datagram Protocol
Length: 8
Checksum: 0x5825
UDP Data Area: No more data.
Here we see a ‘normal’ UDP
header with a length of 8 bytes.
More Router Investigation
After noting that the
packets from traceroute appeared to be mal-formed, I
looked into the router packet statistics:
#show ip
traffic
. .
UDP 655 no port
. .
Every time I ran traceroute this "UDP no port" count would increment by the number
of UDP packets sent from traceroute. This indicates
that the router does not recognize the UDP header as is, and never "finds" a
port. This might explain the router`s response: ICMP Port Unreachable.
Ironically, this response is exactly what traceroute
is looking for and translates it as a valid response from an "endpoint"
machine.
Notes:
* I later ran the test with Redhat version 8.0. The packets generated were exactly the same.
For those of you that
prefer to examine the raw tcpdump data:
Traceroute dump:
09:03:46.298411 216.249.144.221.32772 > 216.249.144.222.135: udp 10 [ttl 1]
4500 0026 4b66 0000 0111 9ab2 d8f9 90dd
d8f9 90de 8004 0087 0012 bc8f 0101 d211
663e b1ae 0400
09:03:46.298411 216.249.144.225 > 216.249.144.221: icmp: 216.249.144.222 udp port 135 unreachable [tos 0xc0]
45c0 0038 00c9 0000 ff01 e689 d8f9 90e1
d8f9 90dd 0303 bfcf 0000 0000 4500 0026
4b66 0000 0111 9ab2 d8f9 90dd d8f9 90de
8004 0087 0012 bc8f
09:03:56.328411 216.249.144.221.32772 > 216.249.144.222.136: udp 10 [ttl 1]
4500 0026 4b67 0000 0111 9ab1 d8f9 90dd
d8f9 90de 8004 0088 0012 bc38 0201 dc11
663e a604 0500
09:03:56.328411 216.249.144.225 > 216.249.144.221: icmp: 216.249.144.222 udp port 136 unreachable [tos 0xc0]
45c0 0038 00ca 0000 ff01 e688 d8f9 90e1
d8f9 90dd 0303 c025 0000 0000 4500 0026
4b67 0000 0111 9ab1 d8f9 90dd d8f9 90de
8004 0088 0012 bc38
09:03:56.328411 216.249.144.221.32772 > 216.249.144.222.netbios-ns: NBT UDP PACKET(137): OPUNKNOWN; NEGATIVE;
RESPONSE; BROADCAST [ttl 1]
4500 0026 4b68 0000 0111 9ab0 d8f9 90dd
d8f9 90de 8004 0089 0012 8831 0301 dc11
663e d90a 0500
nmap Dump:
09:01:42.778411 216.249.144.221.54145 > 216.249.144.222.135: udp 0
4500 001c afd7 0000 3a11 fd4a d8f9 90dd
d8f9 90de d381 0087 0008 5826
09:01:42.778411 216.249.144.222.135 > 216.249.144.221.54145: udp 84
4500 0070 0075 0000 7f11 6759 d8f9 90de
d8f9 90dd 0087 d381 005c f3ee 0406 0000
1000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 c130 823c 0000 0000 0000 0000
0000 0000 0000 0400 0000 0000 0800 001c