tp_output.c

Go to the documentation of this file.
00001 /* vim: set tabstop=4: */
00002 /*
00003  * This file is part of TraceProto.
00004  * Copyright 2004-2005 Eric Hope and others; see the AUTHORS file for details.
00005  *
00006  * TraceProto is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * TraceProto is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with TraceProto; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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 /* HAVE_LIBDMALLOC */
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 /* as close as possible to the original traceroute
00184  * needs a bit of work to make it match exactly */
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  * traceproto standard format, somewhat more readable than the original
00272  * but still fairly space efficient
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         /*              printf ( "\t%s", std_packet_id [ packet_type ] ); */
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                 /* static int host_column  = 9; */
00445                 /* static int as_column; */
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                 /* start the curses stuff */
00459                 initscr ( );
00460                 intrflush ( stdscr, 1 );
00461 
00462                 /* header info */
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                 /* print the stats header */
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                         if ( behavior.as_discovery == YES )
00506                         {
00507                                 find_as ( inet_ntoa ( * from ) );
00508                                 printw ( "  %s from %s (%s) [%s]\n",
00509                                         curses_packet_id [ packet_type ],
00510                                         libnet_addr2name4 ( from->s_addr, behavior.libnet_resolve_choice ),
00511                                         inet_ntoa ( * from ),
00512                                         as_string );
00513                         } else {
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 /*      fflush ( stdout ); */
00559 
00560         if ( from != 0 )
00561                 previous_in_addr = * from;
00562 
00563 #else /* ! TP_USE_CURSES */
00564 
00565         /* If the curses libs aren't available,
00566            print and error and degrade gracefully. */
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 /* TP_USE_CURSES */
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 }

Generated on Wed Sep 16 11:08:43 2009 for traceproto by  doxygen 1.5.4