00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <libnet.h>
00022 #include <pcap.h>
00023 #include <unistd.h>
00024 #include <errno.h>
00025 #include <sys/time.h>
00026 #include <stdio.h>
00027 #include <sys/types.h>
00028 #include <arpa/inet.h>
00029 #include <signal.h>
00030 #include <string.h>
00031 #include <stdlib.h>
00032 #include <netinet/in.h>
00033 #include <ctype.h>
00034 #include <time.h>
00035
00036 #include "traceproto.h"
00037 #include "tp_miscfunc.h"
00038 #include "tp_output.h"
00039 #include "config.h"
00040 #include "tp_as.h"
00041
00042 #if defined ( HAVE_NCURSES_H )
00043 #include <ncurses.h>
00044 #elif defined ( HAVE_NCURSES_NCURSES_H )
00045 #include <ncurses/ncurses.h>
00046 #elif defined ( HAVE_CURSES_H )
00047 #include <curses.h>
00048 #endif
00049
00050 #if defined ( HAVE_LIBNCURSES )
00051 #define TP_USE_CURSES 1
00052 #elif defined ( HAVE_LIBCURSES )
00053 #define TP_USE_CURSES 1
00054 #endif
00055
00056 #ifdef HAVE_LIBDMALLOC
00057 #include <dmalloc.h>
00058 #endif
00059
00060 void report_none ( int output_item, __attribute__((__unused__)) struct in_addr * from, __attribute__((__unused__)) int packet_type )
00061 {
00062 if ( output_item == TP_OUT_HEADER )
00063 {
00064 printf ( "%s to %s (%s), %d hops max\n",
00065 state.prog,
00066 behavior.target,
00067 behavior.target_reverse,
00068 behavior.max_ttl );
00069 if ( behavior.default_if == NO )
00070 printf ( "using interface %s\n", behavior.interface );
00071 if ( behavior.timestamp == YES )
00072 printf ( "trace time: %s\n", behavior.timestamp_str );
00073 }
00074
00075 if ( output_item == TP_OUT_FOOTER )
00076 hop_audit ( );
00077
00078 fflush ( stdout );
00079
00080 return;
00081 }
00082
00083 void report_minimum ( int output_item, __attribute__((__unused__)) struct in_addr * from, int packet_type )
00084 {
00085 const char * minimal_packet_id[] = {
00086 " ",
00087 "*",
00088 "S",
00089 "A",
00090 "S",
00091 "S",
00092 "R",
00093 "R",
00094 "F",
00095 "U",
00096 "X",
00097 "P",
00098 "H",
00099 "N",
00100 "I",
00101 "E",
00102 "H",
00103 "?"
00104 };
00105
00106 switch ( output_item )
00107 {
00108 case TP_OUT_HEADER:
00109 if ( behavior.timestamp == YES )
00110 printf ( "%s\n", behavior.timestamp_str );
00111 break;
00112 case TP_OUT_HOP_NUMBER:
00113 printf ( "%d ", state.current_hop );
00114 break;
00115 case TP_OUT_HOP_INFO:
00116 printf ( "%s ", minimal_packet_id [ packet_type ] );
00117 if ( ( state.packets_this_hop + 1 ) == behavior.packets_per_hop )
00118 printf ( "\n" );
00119 break;
00120 case TP_OUT_FOOTER:
00121 hop_audit ( );
00122 break;
00123 }
00124
00125 fflush ( stdout );
00126
00127 return;
00128 }
00129
00130 void report_scriptable ( int output_item, struct in_addr * from, int packet_type )
00131 {
00132 const char * script_packet_id[] = {
00133 "NULL",
00134 "NR",
00135 "TS",
00136 "TA",
00137 "TSA",
00138 "TSC",
00139 "TR",
00140 "TAR",
00141 "TF",
00142 "U",
00143 "ITX",
00144 "IPU",
00145 "IHU",
00146 "INU",
00147 "I",
00148 "ER",
00149 "PRO",
00150 "O",
00151 };
00152 switch ( output_item )
00153 {
00154 case TP_OUT_HEADER:
00155 if ( behavior.timestamp == YES )
00156 printf ( "%s\n", behavior.timestamp_str );
00157 break;
00158 case TP_OUT_HOP_NUMBER:
00159 break;
00160 case TP_OUT_HOP_INFO:
00161 if ( packet_type == TP_TYPE_NR )
00162 {
00163 printf ( "%d 0.0.0.0 %s 0\n",
00164 state.current_hop,
00165 script_packet_id [ packet_type ] );
00166 } else {
00167 printf ( "%d %s %s %3g\n",
00168 state.current_hop,
00169 inet_ntoa ( * from ),
00170 script_packet_id [ packet_type ],
00171 state.trip_time );
00172 }
00173 break;
00174 case TP_OUT_FOOTER:
00175 hop_audit ( );
00176 break;
00177 }
00178 fflush ( stdout );
00179
00180 return;
00181 }
00182
00183
00184
00185 void report_classic ( int output_item, struct in_addr * from, int packet_type )
00186 {
00187 static struct in_addr previous_in_addr;
00188
00189 const char * classic_packet_id[] = {
00190 " ",
00191 "*",
00192 " ",
00193 " ",
00194 " ",
00195 " ",
00196 "!R",
00197 "!R",
00198 " ",
00199 " ",
00200 " ",
00201 "!P",
00202 "!H",
00203 "!N",
00204 " ",
00205 "*",
00206 "!H",
00207 "!?"
00208 };
00209
00210 switch ( output_item )
00211 {
00212 case TP_OUT_HEADER:
00213 printf ( "%s to %s (%s), %d hops max\n",
00214 state.prog,
00215 behavior.target,
00216 behavior.target_reverse,
00217 behavior.max_ttl );
00218 if ( behavior.default_if == NO )
00219 printf ( "using interface %s\n", behavior.interface );
00220 if ( behavior.timestamp == YES )
00221 printf ( "trace time: %s\n", behavior.timestamp_str );
00222 break;
00223 case TP_OUT_HOP_NUMBER:
00224 printf ( "%d ", state.current_hop );
00225 previous_in_addr.s_addr = ( unsigned long ) NULL;
00226 break;
00227 case TP_OUT_HOP_INFO:
00228 if ( from != NULL && previous_in_addr.s_addr != from->s_addr )
00229 {
00230 if ( previous_in_addr.s_addr != ( unsigned long ) NULL )
00231 printf ( "\n\t" );
00232 if ( behavior.as_discovery == YES )
00233 {
00234 find_as ( inet_ntoa ( * from ) );
00235 printf ( "%s (%s) [%s] ",
00236 libnet_addr2name4 ( from->s_addr,
00237 behavior.libnet_resolve_choice ),
00238 inet_ntoa ( * from ),
00239 as_string );
00240 } else {
00241 printf ( "%s (%s) ",
00242 libnet_addr2name4 ( from->s_addr,
00243 behavior.libnet_resolve_choice ),
00244 inet_ntoa ( * from ) );
00245 }
00246 }
00247 if ( packet_type == TP_TYPE_NR )
00248 printf ( "* " );
00249 else
00250 printf ( "%3g ms %s ",
00251 state.trip_time,
00252 classic_packet_id [ packet_type ] );
00253
00254 if ( ( state.packets_this_hop + 1 ) >= behavior.packets_per_hop )
00255 printf ( "\n" );
00256
00257 break;
00258 case TP_OUT_FOOTER:
00259 hop_audit ( );
00260 break;
00261 }
00262
00263 fflush ( stdout );
00264 if ( from != 0 )
00265 previous_in_addr = * from;
00266
00267 return;
00268 }
00269
00270
00271
00272
00273
00274 void report_std ( int output_item, struct in_addr * from, int packet_type )
00275 {
00276 static struct in_addr previous_in_addr;
00277
00278 const char * std_packet_id[] = {
00279 "null",
00280 "no response",
00281 "TCP Syn",
00282 "TCP Ack",
00283 "TCP Syn Ack",
00284 "TCP Syn Ecn",
00285 "TCP Reset",
00286 "TCP Ack Reset",
00287 "TCP Fin",
00288 "UDP",
00289 "ICMP Time Exceeded",
00290 "Port Unreachable",
00291 "Host Unreachable",
00292 "Network Unreachable",
00293 "ICMP",
00294 "Echo Reply",
00295 "ICMP Prohibited",
00296 "Unknown"
00297 };
00298
00299 switch ( output_item )
00300 {
00301 case TP_OUT_HEADER:
00302 printf ( "%s: trace to %s (%s), port %d\n",
00303 state.prog,
00304 behavior.target,
00305 behavior.target_reverse,
00306 packet.dst_port );
00307 if ( behavior.default_if == NO )
00308 printf ( "using interface %s\n", behavior.interface );
00309 if ( behavior.timestamp == YES )
00310 printf ( "trace time: %s\n", behavior.timestamp_str );
00311 break;
00312 case TP_OUT_HOP_NUMBER:
00313 printf ( "ttl %d:", state.current_hop );
00314 previous_in_addr.s_addr = ( unsigned long ) NULL;
00315 break;
00316 case TP_OUT_HOP_INFO:
00317 if ( from != NULL && previous_in_addr.s_addr != from->s_addr )
00318 {
00319 if ( previous_in_addr.s_addr != ( unsigned long ) NULL )
00320 printf ( "\n\t" );
00321 if ( behavior.as_discovery == YES )
00322 {
00323 find_as ( inet_ntoa ( * from ) );
00324 printf ( " %s from %s (%s) [%s]\n",
00325 std_packet_id [ packet_type ],
00326 libnet_addr2name4 ( from->s_addr, behavior.libnet_resolve_choice ),
00327 inet_ntoa ( * from ),
00328 as_string );
00329 } else {
00330 printf ( " %s from %s (%s)\n",
00331 std_packet_id [ packet_type ],
00332 libnet_addr2name4 ( from->s_addr, behavior.libnet_resolve_choice ),
00333 inet_ntoa ( * from ) );
00334 }
00335 }
00336 if ( packet_type == TP_TYPE_NR )
00337
00338 printf ( "%s ", std_packet_id [ packet_type ] );
00339 else
00340 printf ( "\t%#.5g ms", state.trip_time );
00341
00342 if ( ( state.packets_this_hop + 1 ) == behavior.packets_per_hop )
00343 printf ( "\n" );
00344 break;
00345 case TP_OUT_FOOTER:
00346 hop_audit ( );
00347 break;
00348 }
00349
00350 fflush ( stdout );
00351 if ( from != 0 )
00352 previous_in_addr = * from;
00353
00354 return;
00355 }
00356
00357 void report_graphic ( int output_item, struct in_addr * from, int packet_type )
00358 {
00359 int i;
00360 static struct in_addr previous_in_addr;
00361
00362 const char * graphic_packet_id[] = {
00363 "null",
00364 "no response",
00365 "TCP Syn",
00366 "TCP Ack",
00367 "TCP Syn Ack",
00368 "TCP Syn Ecn",
00369 "TCP Reset",
00370 "TCP Ack Reset",
00371 "TCP Fin",
00372 "UDP",
00373 "ICMP Time Exceeded",
00374 "Port Unreachable",
00375 "Host Unreachable",
00376 "Network Unreachable",
00377 "ICMP",
00378 "Echo Reply",
00379 "ICMP Prohibited",
00380 "Unknown"
00381 };
00382
00383 switch ( output_item )
00384 {
00385 case TP_OUT_HEADER:
00386 printf ( "%s: trace to %s, port %d\n",
00387 state.prog,
00388 behavior.target,
00389 packet.dst_port );
00390 if ( behavior.default_if == NO )
00391 printf ( "using interface %s\n", behavior.interface );
00392 if ( behavior.timestamp == YES )
00393 printf ( "trace time: %s\n", behavior.timestamp_str );
00394 break;
00395 case TP_OUT_HOP_NUMBER:
00396 printf ( "ttl %d: ", state.current_hop );
00397 break;
00398 case TP_OUT_HOP_INFO:
00399 if ( from != NULL && previous_in_addr.s_addr != from->s_addr )
00400 {
00401 if ( behavior.as_discovery == YES )
00402 {
00403 find_as ( inet_ntoa ( * from ) );
00404 printf ( "%s from %s (%s) [%s]\n",
00405 graphic_packet_id [ packet_type ],
00406 libnet_addr2name4 ( from->s_addr, behavior.libnet_resolve_choice ),
00407 inet_ntoa ( * from ),
00408 as_string );
00409 } else {
00410 printf ( "%s from %s (%s)\n",
00411 graphic_packet_id [ packet_type ],
00412 libnet_addr2name4 ( from->s_addr, behavior.libnet_resolve_choice ),
00413 inet_ntoa ( * from ) );
00414 }
00415 }
00416 if ( packet_type == TP_TYPE_NR )
00417 state.trip_time = 0;
00418
00419 for ( i = 0; i < ( int ) state.trip_time; i++ )
00420 printf ( "#" );
00421
00422 printf ( " %#.5g ms\n", state.trip_time );
00423
00424 if ( ( state.packets_this_hop + 1 ) == behavior.packets_per_hop )
00425 printf ( "\n" );
00426 break;
00427 case TP_OUT_FOOTER:
00428 hop_audit ( );
00429 break;
00430 }
00431
00432 fflush ( stdout );
00433 if ( from != 0 )
00434 previous_in_addr = * from;
00435
00436 return;
00437 }
00438
00439 void report_curses ( int output_item, struct in_addr * from, __attribute__((__unused__)) int packet_type )
00440 {
00441 static struct in_addr previous_in_addr;
00442 static int stats_start_line = 4;
00443 static int ttl_column = 0;
00444
00445
00446 static int stats_column = 43;
00447 static int stats_len = 36;
00448 static int other_x;
00449 static int low_point = 4;
00450 int low_point_test;
00451
00452 #ifdef TP_USE_CURSES
00453
00454 switch ( output_item )
00455 {
00456 case TP_OUT_HEADER:
00457
00458
00459 initscr ( );
00460 intrflush ( stdscr, 1 );
00461
00462
00463 move ( 0, 0 );
00464 printw ( "%s: trace to %s (%s), port %d\n",
00465 state.prog,
00466 behavior.target,
00467 behavior.target_reverse,
00468 packet.dst_port );
00469 if ( behavior.default_if == NO )
00470 printw ( "using interface %s\n", behavior.interface );
00471 if ( behavior.timestamp == YES )
00472 printw ( "trace time: %s\n", behavior.timestamp_str );
00473 refresh ( );
00474
00475 stats_column = COLS - stats_len - 2;
00476 getyx ( stdscr, stats_start_line, other_x );
00477 stats_start_line += 1;
00478
00479
00480 move ( stats_start_line - 1, ttl_column );
00481 printw ( "ttl : hostname" );
00482 move ( stats_start_line - 0, ttl_column );
00483 printw ( "---------------" );
00484 move ( stats_start_line - 1, stats_column );
00485 printw ( " last min ave max rcvd lost" );
00486 move ( stats_start_line - 0, stats_column );
00487 printw ( " ------------------------------------\n" );
00488 refresh ( );
00489
00490 break;
00491
00492 case TP_OUT_HOP_NUMBER:
00493 move ( stats_start_line + state.current_hop, 0 );
00494 refresh ( );
00495 printw ( "ttl %d: ", state.current_hop );
00496 previous_in_addr.s_addr = ( unsigned long ) NULL;
00497 break;
00498
00499 case TP_OUT_HOP_INFO:
00500 if ( from != NULL && previous_in_addr.s_addr != from->s_addr )
00501 {
00502 if ( previous_in_addr.s_addr != ( unsigned long ) NULL )
00503 printw ( "\n\t" );
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515 printw ( "%s",
00516 libnet_addr2name4 ( from->s_addr, behavior.libnet_resolve_choice ) );
00517
00518 }
00519 move ( stats_start_line + state.current_hop, stats_column );
00520 refresh ( );
00521 printw ( " %#.5g %#.5g %#.5g %#.5g %3d %3d",
00522 state.trip_time,
00523 state.hop_record[ state.current_hop ].min_time,
00524 state.hop_record[ state.current_hop ].ave_time,
00525 state.hop_record[ state.current_hop ].max_time,
00526 state.hop_record[ state.current_hop ].num_packets,
00527 state.hop_record[ state.current_hop ].lost_packets );
00528
00529 if ( ( state.packets_this_hop + 1 ) == behavior.packets_per_hop )
00530 printw ( "\n" );
00531
00532 getyx ( stdscr, low_point_test, other_x );
00533 low_point = ( low_point_test > low_point ) ? low_point_test : low_point;
00534
00535 break;
00536 case TP_OUT_FOOTER:
00537
00538 move ( low_point, 0 );
00539 refresh ( );
00540 endwin ( );
00541 delwin( stdscr );
00542
00543 printf ( "\n%s: trace to %s (%s), port %d\n",
00544 state.prog,
00545 behavior.target,
00546 behavior.target_reverse,
00547 packet.dst_port );
00548 if ( behavior.default_if == NO )
00549 printf ( "using interface %s\n", behavior.interface );
00550 if ( behavior.timestamp == YES )
00551 printf ( "trace time: %s\n", behavior.timestamp_str );
00552
00553 hop_audit ( );
00554 break;
00555 }
00556
00557 refresh ( );
00558
00559
00560 if ( from != 0 )
00561 previous_in_addr = * from;
00562
00563 #else
00564
00565
00566
00567 printf ( "curses interface unavailable\n" );
00568 behavior.output_style = TP_STD_OUTPUT;
00569 behavior.report = report_std;
00570 behavior.report( TP_OUT_HEADER, NULL, 0 );
00571
00572 #endif
00573
00574 return;
00575 }
00576
00577
00578
00579
00580 void usage( void )
00581 {
00582 size_t i;
00583 const char * usage_str[] = {
00584 "usage:",
00585 "\ttraceproto [options] destination",
00586 "\t-p protocol (default tcp)",
00587 "\t\tcurrently available: tcp, udp, and icmp",
00588 "\t-d minimum (or only) destination port (default 80)",
00589 "\t-D maximum destination port",
00590 "\t-s minimum source port (default 10240)",
00591 "\t-S maximum source port",
00592 "\t-m minimum ttl (default 1)",
00593 "\t-M maximum ttl (default 30)",
00594 "\t-w wait timeout (default 5 sec)",
00595 "\t-W wait timeout before sending a new packet (default 0 ms)",
00596 "\t-a hop accounting (default 2)",
00597 "\t\t 0 == no accounting",
00598 "\t\t 1 == total only",
00599 "\t\t 2 == full accounting",
00600 "\t-P payload byte count (default 12)",
00601 "\t-k comma separated list of hops to skip (default none)",
00602 "\t-c trace continuously without accounting",
00603 "\t-C continuous trace with accounting",
00604 "\t-I number of reoccuring traces",
00605 "\t-H packets per hop (default 3)",
00606 "\t-f set the don't fragment bit",
00607 "\t-F specify the network interface",
00608 "\t-A do AS number lookup",
00609 "\t-T print timestamp",
00610 "\t-i incr/decr source/destination ports",
00611 "\t\t s == decrement source port",
00612 "\t\t S == increment source port (default)",
00613 "\t\t d == decrement destination port",
00614 "\t\t D == increment destination port",
00615 "\t\t n == static source port",
00616 "\t\t N == static destination port (default)",
00617 "\t\t Note: nN may result in inaccurate responses",
00618 "\t-o output style",
00619 "\t\t s == standard output (default)",
00620 "\t\t g == graphical output",
00621 "\t\t c == classic output",
00622 "\t\t m == minimal output",
00623 "\t\t p == scriptable output",
00624 "\t\t n == no individual hop output, accounting only",
00625 "\t\t C == (n)curses output",
00626 "\t-t tcp flags to use",
00627 "\t\t S == SYN (default)",
00628 "\t\t A == ACK",
00629 "\t\t R == RST",
00630 "\t\t U == URG",
00631 "\t\t P == PUSH",
00632 "\t\t F == FIN",
00633 "\t\t E == ECE",
00634 "\t\t C == CWR",
00635 "\t-R start at max ttl and decrement",
00636 "\t-h this help message",
00637 "\t-v version info",
00638 "",
00639 "Note that you can set generally set illogical or contradictory",
00640 "options if you wish, combining -d 80 and -p icmp is permissible",
00641 "but silly. The option that doesn't make sense is usually ignored.",
00642 "In the case of contradictory options, the last one seen is",
00643 "generally authoritative",
00644 "" };
00645
00646 for ( i = 0; i < sizeof ( usage_str ) / sizeof ( char * ); i++ )
00647 printf ( "%s\n", usage_str [ i ] );
00648 }