Source code: com/act365/net/ping/Traceroute.java
1 /*
2 * JSocket Wrench
3 *
4 * Copyright (C) act365.com October 2003
5 *
6 * Web site: http://www.act365.com/wrench
7 * E-mail: developers@act365.com
8 *
9 * The JSocket Wrench library adds support for low-level Internet protocols
10 * to the Java programming language.
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the Free
14 * Software Foundation; either version 2 of the License, or (at your option)
15 * any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
20 * Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * this program; if not, write to the Free Software Foundation, Inc.,
24 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
27 package com.act365.net.ping ;
28
29 import com.act365.net.*;
30 import com.act365.net.icmp.*;
31 import com.act365.net.ip.*;
32 import com.act365.net.udp.*;
33
34 import java.net.*;
35 import java.util.*;
36
37 /**
38 Implements the well-known Traceroute network utility. The app supports
39 the broadcast of UDP or ICMP ECHO_REQUEST packets.
40 */
41
42 public class Traceroute {
43
44 /**
45 Executes the Traceroute service.
46 <p>Usage: <code>Traceroute -p protocol -l localhost -d host</code>
47 <p><code>protocol</code> is the protocol to be used for broadcast. The default
48 is ICMP - the alternative is UDP.
49 <p><code>localhost</code> is the local host address, which should be specified
50 if UDP is used. (The information is used to calculate the UDP checksum).
51 <p><code>-d</code> should be specified if debug is required.
52 <p><code>host</code> is the remote hostname and is mandatory.
53 */
54
55 public static void main( String[] args ){
56
57 final String errortext = "Usage: Traceroute -p protocol -l localhost -d host";
58
59 if( args.length == 0 ){
60 System.err.println( errortext );
61 System.exit( 1 );
62 }
63
64 String hostname = args[ args.length - 1 ] ,
65 localhost = null ;
66
67 String protocollabel = null ;
68
69 boolean debug = false ;
70
71 int i = 0 ;
72
73 while( i < args.length - 1 ){
74 if( args[ i ].equals("-p") && i < args.length - 2 ){
75 protocollabel = args[ ++ i ];
76 if( ! protocollabel.equalsIgnoreCase("ICMP") &&
77 ! protocollabel.equalsIgnoreCase("UDP") ){
78 System.err.println("Unsupported protocol");
79 System.exit( 2 );
80 }
81 } else if( args[ i ].equals("-l") && i < args.length - 2 ){
82 localhost = args[ ++ i ];
83 } else if( args[ i ].equals("-d") ){
84 debug = true ;
85 } else {
86 System.err.println( errortext );
87 System.exit( 1 );
88 }
89 ++ i ;
90 }
91
92 try {
93 SocketUtils.setProtocol("RawICMP");
94 } catch ( java.io.IOException e ) {
95 System.err.println("Unsupported protocol");
96 System.exit( 4 );
97 }
98
99 int protocol = protocollabel instanceof String && protocollabel.equalsIgnoreCase("UDP")
100 ? SocketConstants.IPPROTO_UDP : SocketConstants.IPPROTO_ICMP ;
101
102 new SocketWrenchSession();
103
104 InetAddress hostaddr = null ,
105 localaddr = null ;
106
107 try {
108 hostaddr = InetAddress.getByName( hostname );
109 if( localhost instanceof String ){
110 localaddr = InetAddress.getByName( localhost );
111 }
112 } catch ( UnknownHostException e ) {
113 System.err.println( e.getMessage() );
114 System.exit( 5 );
115 }
116
117 if( protocol == SocketConstants.IPPROTO_UDP && localaddr == null ){
118 System.err.println("localhost must be defined if RawUDP is to be used");
119 System.exit( 6 );
120 }
121
122 DatagramSocket socket = null ;
123
124 try {
125 socket = new DatagramSocket();
126 } catch ( SocketException e ) {
127 System.err.println( e.getMessage() );
128 System.exit( 7 );
129 }
130
131 try {
132
133 final int maxdatagramlength = 512 ;
134
135 byte[] recvbuffer = new byte[ maxdatagramlength ] ,
136 timebuffer = new byte[ 8 ] ,
137 messagebuffer ,
138 sendbuffer ;
139
140 DatagramPacket packet ;
141
142 ICMPWriter writer = new ICMPWriter( (short) socket.hashCode() );
143
144 ICMPReader reader = new ICMPReader( (short) socket.hashCode() );
145
146 ICMPMessage message = null ;
147
148 float sumdt = 0 ,
149 mindt = Float.MAX_VALUE ,
150 maxdt = Float.MIN_VALUE ;
151
152 short ttl = 0 ;
153
154 int sourceport = 42000 ,
155 destinationport = 64000 ;
156
157 while( message == null || message.type != ICMP.ICMP_ECHOREPLY || message.type != ICMP.ICMP_DEST_UNREACH ){
158
159 SocketUtils.longToBytes( new Date().getTime() , timebuffer , 0 );
160
161 switch( protocol ){
162
163 case SocketConstants.IPPROTO_ICMP:
164 messagebuffer = writer.write( ICMP.ICMP_ECHO , (byte) 0 , timebuffer );
165 break;
166
167 case SocketConstants.IPPROTO_UDP:
168 messagebuffer = UDPWriter.write( localaddr.getAddress() ,
169 (short) sourceport ++ ,
170 hostaddr.getAddress() ,
171 (short) destinationport ++ ,
172 timebuffer ,
173 timebuffer.length );
174 break;
175
176 default:
177 messagebuffer = new byte[0];
178 }
179
180
181 sendbuffer = IP4Writer.write( IP4.TOS_ICMP ,
182 ++ ttl ,
183 (byte) protocol ,
184 localaddr != null ? localaddr.getAddress() : new byte[ 4 ] ,
185 hostaddr.getAddress() ,
186 messagebuffer );
187
188 if( debug ){
189 System.err.println("SEND:");
190 SocketUtils.dump( System.err , sendbuffer , 0 , sendbuffer.length );
191 }
192
193 socket.send( new DatagramPacket( sendbuffer , sendbuffer.length , hostaddr , 0 ) );
194
195 packet = new DatagramPacket( recvbuffer , maxdatagramlength );
196
197 socket.receive( packet );
198
199 if( ( message = reader.read( packet.getData() , packet.getLength() , 20 , false ) ) != null ){
200
201 if( debug ){
202 System.err.println("RECEIVE:");
203 SocketUtils.dump( System.err , packet.getData() , 0 , packet.getLength() );
204 }
205
206 if( message.type == ICMP.ICMP_TIME_EXCEEDED ||
207 message.type == ICMP.ICMP_ECHOREPLY ||
208 message.type == ICMP.ICMP_DEST_UNREACH ){
209 System.out.println( packet.getAddress() );
210 } else {
211 System.out.println( ICMP.typelabels[ message.type ] );
212 }
213 }
214 }
215
216 } catch ( Exception e ) {
217 System.err.println( e.getMessage() );
218 System.exit( 8 );
219 }
220 }
221 }
222