traceproto.c

Go to the documentation of this file.
00001 /* vim: set tabstop=4: */
00002 /* This file is part of TraceProto. */
00003 
00031 #include <libnet.h>
00032 #include <pcap.h>
00033 #include <errno.h>
00034 #include <sys/time.h>
00035 #include <stdio.h>
00036 #include <sys/types.h>
00037 #include <arpa/inet.h>
00038 #include <signal.h>
00039 #include <string.h>
00040 #include <stdlib.h>
00041 #include <netinet/in.h>
00042 #include <netdb.h>
00043 #include <ctype.h>
00044 #include <unistd.h>
00045 #include <assert.h>
00046 
00047 #include "traceproto.h"
00048 #include "config.h"
00049 #include "tp_as.h"
00050 #include "tp_miscfunc.h"
00051 #include "tp_output.h"
00052 #include "tp_packet.h"
00053 
00054 #ifdef HAVE_LIBDMALLOC
00055 #include <dmalloc.h>
00056 #endif /* HAVE_LIBDMALLOC */
00057 
00058 int main( int argc, char * argv[] )
00059 {
00060 
00061 
00062         int cmd_arg, i, l;
00063         u_int on = 1;
00064         char * opt_string;
00065         char * env_string;
00066 
00067 #ifdef HAVE_LIBCAP
00068         dropexcesscapabilities();
00069 #endif /* HAVE_LIBCAP */
00070 
00071 /*
00072  * regularize the program name
00073  */
00074         if ( reg_name( argv[ 0 ] ) == 0 )
00075         {
00076                 printf ( "setup error, unable to parse program name\n" );
00077                 tixe ( tixe_cleanup, 1 );
00078         }
00079 
00080 /*
00081  * set the defaults
00082  */
00083         behavior.continuous = NO;
00084         behavior.packets_per_hop = 3;
00085         behavior.src_port_incr = 1;     /* src port */
00086         behavior.dst_port_incr = 0;     /* dst port */
00087         behavior.min_src_port = 10240;
00088         behavior.rndm_src_port = YES;
00089         behavior.min_dst_port = 80;
00090         behavior.max_ttl = 30;                  /* hops */
00091         behavior.min_ttl = 1;                   /* hop(s) */
00092         behavior.wait_timeout = 5;              /* seconds */
00093         behavior.wait_between_packets = 100;    /* milliseconds */
00094         behavior.protocol = "tcp";
00095         behavior.tcp_resets = YES;
00096         behavior.account_level = TP_ACCOUNT_FULL;
00097         behavior.report = report_std;
00098         behavior.do_audit = NO;
00099         behavior.do_audit_exit = NO;
00100         behavior.do_skip = NO;
00101         behavior.as_discovery = NO;
00102         behavior.output_style = TP_STD_OUTPUT;
00103         behavior.payload_size = 12;
00104         behavior.libnet_resolve_choice = LIBNET_RESOLVE;
00105         behavior.hop_incr_unit = 1;
00106         behavior.timestamp = NO;
00107         behavior.timestamp_style = TP_TIMESTAMP_STD;
00108         behavior.filter_text = "( host %s and dst port %d and src port %d ) or ( icmp[12:2] == %d )";
00109         behavior.default_if = YES;
00110         memset ( behavior.interface, '\0', TP_IF_ARRAY );
00111         strncpy ( behavior.interface, "any", TP_IF_ARRAY - 1 ); 
00112 
00113         packet.protocol_number = IPPROTO_TCP;
00114         packet.payload = 0;
00115         packet.frag_bit = 0;
00116         packet.tcp_flags = TH_SYN;
00117         packet.ip_packet_len = LIBNET_IPV4_H;
00118 
00119         state.tcp_h  = LIBNET_PTAG_INITIALIZER;
00120         state.udp_h  = LIBNET_PTAG_INITIALIZER;
00121         state.icmp_h = LIBNET_PTAG_INITIALIZER;
00122         state.ip_h   = LIBNET_PTAG_INITIALIZER;
00123         state.incr_error = NO;
00124         state.target_response = NO;
00125         state.continuous_count = ( int ) NULL;
00126 
00127         /*
00128          * If called as "traceroute" try to be a drop-in replacement.
00129          * Currently we aren't an exact copy, but most of the differences
00130          * are a matter of different command line flags for the original
00131          * features.  We can more or less produce the same output behavior. 
00132          */
00133         if ( strncmp ( state.prog, "traceroute", 11 ) == 0 )
00134         {
00135                 behavior.output_style = TP_CLASSIC_OUTPUT;
00136                 behavior.protocol = "udp";
00137                 behavior.min_dst_port = 32768 + 666;
00138                 behavior.account_level = TP_ACCOUNT_NONE;
00139                 behavior.src_port_incr = 0;     /* src port */
00140                 behavior.dst_port_incr = 1;     /* dst port */
00141         }
00142 
00143 /*
00144  * grab the relavent env variables
00145  *
00146  * NOTE: the values gathered from the env
00147  * overwrite the defaults set above and are 
00148  * overwritten in turn by any cmd line flags 
00149  * that happen to be set below
00150  *
00151  * These should always have an else or a default so that the
00152  * prog still does rational things if the user puts in a weird
00153  * value.
00154  */
00155 
00156         env_string = NULL;
00157         if ( ( env_string = getenv ( "TP_TIMESTAMP_STYLE" ) ) != NULL )
00158         {
00159                 if ( strncmp ( env_string, "std", 3 ) == 0 )
00160                         behavior.timestamp_style = TP_TIMESTAMP_STD;
00161                 else if ( strncmp ( env_string, "us", 2 ) == 0 )
00162                         behavior.timestamp_style = TP_TIMESTAMP_US;
00163                 else if ( strncmp ( env_string, "desc", 4 ) == 0 )
00164                         behavior.timestamp_style = TP_TIMESTAMP_DESCEND;
00165                 else if ( strncmp ( env_string, "epoch", 5 ) == 0 )
00166                         behavior.timestamp_style = TP_TIMESTAMP_EPOCH;
00167                 else
00168                         behavior.timestamp_style = TP_TIMESTAMP_STD;
00169         }
00170         
00171         env_string = NULL;
00172         if ( ( env_string = getenv ( "TP_DEFAULT_IF" ) ) != NULL )
00173         {
00174                 strncpy ( behavior.interface, env_string, TP_IF_ARRAY - 1 );
00175                 behavior.default_if = NO;
00176         }
00177 
00178         env_string = NULL;
00179         if ( ( env_string = getenv ( "TP_OUTPUT_STYLE" ) ) != NULL )
00180         {
00181                 if ( 
00182                         strncmp ( env_string, "stand", 5 ) == 0 ||
00183                         strncmp ( env_string, "std",   3 ) == 0 ||
00184                         strncmp ( env_string, "s",     1 ) == 0    )
00185                 {
00186                                 behavior.output_style = TP_STD_OUTPUT;
00187                                 behavior.report = report_std;
00188                 } else if (     
00189                         strncmp ( env_string, "graph", 5 ) == 0 ||
00190                         strncmp ( env_string, "g",     1 ) == 0    )
00191                 {
00192                                 behavior.output_style = TP_GRAPHIC_OUTPUT;
00193                                 behavior.report = report_graphic;
00194                 } else if (
00195                         strncmp ( env_string, "class", 5 ) == 0 ||
00196                         strncmp ( env_string, "c",     1 ) == 0    )
00197                 {
00198                                 behavior.output_style = TP_CLASSIC_OUTPUT;
00199                                 behavior.report = report_classic;
00200                 } else if (
00201                         strncmp ( env_string, "no",    2 ) == 0 ||
00202                         strncmp ( env_string, "n",     1 ) == 0    )
00203                 {
00204                                 behavior.output_style = TP_NO_OUTPUT;
00205                                 behavior.report = report_none;
00206                 } else if (
00207                         strncmp ( env_string, "min",   3 ) == 0 ||
00208                         strncmp ( env_string, "m",     1 ) == 0    )
00209                 {
00210                                 behavior.output_style = TP_MIN_OUTPUT;
00211                                 behavior.report = report_minimum;
00212                 } else if ( 
00213                         strncmp ( env_string, "script", 6 ) == 0 ||
00214                         strncmp ( env_string, "p",      1 ) == 0    )
00215                 {
00216                                 behavior.output_style = TP_SCRIPT_OUTPUT;
00217                                 behavior.report = report_scriptable;
00218                 } else if ( 
00219                         strncmp ( env_string, "curs",  4 ) == 0 ||
00220                         strncmp ( env_string, "ncurs", 5 ) == 0 ||
00221                         strncmp ( env_string, "C",     1 ) == 0    )
00222                 {
00223                                 behavior.output_style = TP_CURSES_OUTPUT;
00224                                 behavior.report = report_curses;
00225                                 tixe_cleanup.curses_end = YES;
00226                 } else {
00227                                 behavior.output_style = TP_STD_OUTPUT;
00228                                 behavior.report = report_std;
00229                 }
00230         } /* end if getenv ( "TP_OUTPUT_STYLE" ) */
00231         
00232 
00233 
00234 /*
00235  * get command line args
00236  */
00237         while ( ( cmd_arg = getopt ( argc, argv,
00238                         "cCvnhRfATp:i:I:D:r:t:k:o:a:s:S:H:d:M:m:w:W:F:p:P:z:"
00239                 ) ) != EOF )
00240         {
00241                 switch ( cmd_arg )
00242                 {
00243                 case 'c':
00244                         behavior.continuous = YES;
00245                         behavior.continuous_accounting = NO;
00246                         break;
00247                 case 'C':
00248                         behavior.continuous = YES;
00249                         behavior.continuous_accounting = YES;
00250                         break;
00251                 case 'I':
00252                         state.continuous_count = atoi ( optarg );
00253                         behavior.continuous = YES;
00254                         break;
00255                 case 'H':
00256                         behavior.packets_per_hop = atoi ( optarg );
00257                         break;
00258                 case 'i':
00259                         /*
00260                          * controls the port number on the two ends
00261                          * possiblities are src/dst and incr/decr/static
00262                          */
00263                         opt_string = optarg;
00264                         for ( i = strlen ( opt_string ); i >= 0; i-- )
00265                         {
00266                                 switch ( opt_string [ i ] )
00267                                 {
00268                                 case 's':
00269                                         behavior.src_port_incr = -1;
00270                                         break;
00271                                 case 'S':
00272                                         behavior.src_port_incr = 1;     /* default */
00273                                         break;
00274                                 case 'd':
00275                                         behavior.dst_port_incr = -1;
00276                                         break;
00277                                 case 'D':
00278                                         behavior.dst_port_incr = 1;
00279                                         break;
00280                                 case 'n':
00281                                         behavior.src_port_incr = 0;
00282                                         break;
00283                                 case 'N':
00284                                         behavior.dst_port_incr = 0;     /* default */
00285                                         break;
00286                                 case '\0':
00287                                         break;
00288                                 default:
00289                                         state.incr_error = YES;
00290                                         break;
00291                                 }
00292                         }
00293                         break;
00294                 case 'd':
00295                         behavior.min_dst_port = atoi( optarg );
00296                         break;
00297                 case 'D':
00298                         behavior.max_dst_port = atoi( optarg );
00299                         break;
00300                 case 'm':
00301                         behavior.min_ttl = atoi ( optarg );
00302                         break;
00303                 case 'M':
00304                         behavior.max_ttl = atoi( optarg );
00305                         break;
00306                 case 'n':
00307                         behavior.libnet_resolve_choice = LIBNET_DONT_RESOLVE;
00308                         break;
00309                 case 'w':
00310                         /* how long to wait to see if a response turns up */
00311                         behavior.wait_timeout = atoi ( optarg );
00312                         break;
00313                 case 'W':
00314                         /* how long to wait after a response ( or timeout )
00315                          * before sending the next probe */
00316                         behavior.wait_between_packets = atoi ( optarg );
00317                         break;
00318                 case 's':
00319                         behavior.min_src_port = atoi ( optarg );
00320                         behavior.rndm_src_port = NO;
00321                         break;
00322                 case 'S':
00323                         behavior.max_src_port = atoi ( optarg );
00324                         behavior.rndm_src_port = NO;
00325                         break;
00326                 case 'p':
00327                         behavior.protocol = optarg;
00328                         break;
00329                 case 'a':
00330                         behavior.account_level = atoi ( optarg );
00331                         break;
00332                 case 'k':
00333                         /* a list of hops ( ie ttl numbers ) to skip */
00334                         behavior.skip_str = optarg;
00335                         behavior.do_skip = YES;
00336                         break;
00337                 case 'h':
00338                         usage ( );
00339                         tixe ( tixe_cleanup, 0 );
00340                         break;
00341                 case 'v':
00342                         version ( );
00343                         tixe ( tixe_cleanup, 1 );
00344                         break;
00345                 case 'o':
00346                         /* what should the printout look like */
00347                         opt_string = optarg;
00348                         if ( opt_string [ 0 ] == 's' )
00349                         {
00350                                 behavior.output_style = TP_STD_OUTPUT;
00351                                 behavior.report = report_std;
00352                                 break;
00353                         } else if ( opt_string [ 0 ] == 'g' ) {
00354                                 behavior.output_style = TP_GRAPHIC_OUTPUT;
00355                                 behavior.report = report_graphic;
00356                                 break;
00357                         } else if ( opt_string [ 0 ] == 'c' ) {
00358                                 behavior.output_style = TP_CLASSIC_OUTPUT;
00359                                 behavior.report = report_classic;
00360                                 break;
00361                         } else if ( opt_string [ 0 ] == 'C' ) {
00362                                 behavior.output_style = TP_CURSES_OUTPUT;
00363                                 behavior.report = report_curses;
00364                                 break;
00365                         } else if ( opt_string [ 0 ] == 'n' ) {
00366                                 behavior.output_style = TP_NO_OUTPUT;
00367                                 behavior.report = report_none;
00368                                 break;
00369                         } else if ( opt_string [ 0 ] == 'm' ) {
00370                                 behavior.output_style = TP_MIN_OUTPUT;
00371                                 behavior.report = report_minimum;
00372                                 break;
00373                         } else if ( opt_string [ 0 ] == 'p' ) {
00374                                 behavior.output_style = TP_SCRIPT_OUTPUT;
00375                                 behavior.report = report_scriptable;
00376                                 break;
00377                         } else {
00378                                 printf ( "invalid output style: %c\n", * opt_string );
00379                                 usage ( );
00380                                 tixe ( tixe_cleanup, 1 );
00381                         }
00382                         break;
00383                 case 't':
00384                         /* the tcp SYN/ACK/FIN/etc flags */
00385                         opt_string = optarg;
00386                         packet.tcp_flags = parse_flags ( opt_string );
00387                         break;
00388                 case 'P':
00389                         behavior.payload_size = atoi ( optarg );
00390                         break;
00391                 case 'f':
00392                         packet.frag_bit = TP_DONT_FRAG;
00393                         break;
00394                 case 'F':
00395                         strncpy ( behavior.interface, optarg, TP_IF_ARRAY - 1 );
00396                         behavior.default_if = NO;
00397                         break;
00398                 case 'A':
00399                         behavior.as_discovery = YES;
00400                         break;
00401                 case 'T':
00402                         behavior.timestamp = YES;
00403                         make_timestamp ( behavior.timestamp_str );
00404                         break;
00405                 case 'R':
00406                         /* start at the distant end and trace consecutively
00407                          * closer until we get here */
00408                         behavior.hop_incr_unit = -1;
00409                         break;
00410                 case 'z':
00411                         /* undocumented debug flag */
00412                         parse_debug ( optarg );
00413                         break;
00414                 default:
00415                         usage( );
00416                         tixe ( tixe_cleanup, 1 );
00417                         break;
00418                 }
00419         }
00420         behavior.target = argv[optind];
00421 
00422 /*
00423  * set the max ports and starting ports
00424  */
00425         if ( ! behavior.max_src_port )
00426                 behavior.max_src_port = behavior.min_src_port
00427                                         + ((( behavior.max_ttl - behavior.min_ttl )
00428                                         + behavior.packets_per_hop )
00429                                         * behavior.packets_per_hop );
00430 
00431         if ( ! behavior.max_dst_port )
00432                 behavior.max_dst_port = behavior.min_dst_port
00433                                         + ((( behavior.max_ttl - behavior.min_ttl )
00434                                         + behavior.packets_per_hop )
00435                                         * behavior.packets_per_hop );
00436 
00437         if ( behavior.rndm_src_port == YES )
00438         {
00439                 /* this needs to be random, just not very random */
00440                 srand ( ( unsigned int ) getpid() );
00441                 behavior.rndm_src_port = abs ( rand() % 256 );
00442                 behavior.min_src_port += behavior.rndm_src_port;
00443                 behavior.max_src_port += behavior.rndm_src_port;
00444         }
00445 
00446         if ( behavior.src_port_incr == -1 )
00447                 packet.src_port = behavior.max_src_port - behavior.src_port_incr;
00448         else
00449                 packet.src_port = behavior.min_src_port - behavior.src_port_incr;
00450 
00451         if ( behavior.dst_port_incr == -1 )
00452                 packet.dst_port = behavior.max_dst_port - behavior.dst_port_incr;
00453         else
00454                 packet.dst_port = behavior.min_dst_port - behavior.dst_port_incr;
00455 
00456 /*
00457  * sanity checks
00458  */
00459 
00460         /* must be root or the euivalent to use the raw sockets */
00461         if ( geteuid() != 0 )
00462         {
00463                 printf ( "error: root privileges required\n" );
00464                 tixe ( tixe_cleanup, 1 );
00465         }
00466 
00467         /* we really do need to know where to trace to... */
00468         if ( behavior.target == NULL )
00469         {
00470                 printf ( "error: invalid target\n" );
00471                 usage( );
00472                 tixe ( tixe_cleanup, 1 );
00473         }
00474 
00475         if ( state.incr_error != NO )
00476         {
00477                 printf ( "invalid incriment option specified with -i\n" );
00478                 usage ( );
00479                 tixe ( tixe_cleanup, 1 );
00480         }
00481 
00482         /* limit the number of probes per hop */
00483         if ( behavior.packets_per_hop <= 0 || behavior.packets_per_hop > 10 )
00484         {
00485                 printf("packets per hop must be between 1 and 10\n");
00486                 behavior.packets_per_hop = 3;
00487         }
00488 
00489 /*
00490         if ( behavior.continuous == YES && behavior.wait_between_packets < 200 )
00491         {
00492                 behavior.wait_between_packets = 200;
00493         }
00494 */
00495 
00496         /* limits on the continuous count */
00497         if ( state.continuous_count > 2048 )
00498         {
00499                 printf ( "warning: unusually large iteration number set with -I\n" );
00500         }
00501 
00502         /* set the protocol */
00503         if ( strncmp( behavior.protocol, "udp", 3 ) == 0 )
00504         {
00505                 behavior.protocol = "udp";
00506                 packet.protocol_number = IPPROTO_UDP;
00507                 packet.ip_packet_len += LIBNET_UDP_H;
00508         }
00509         else if ( strncmp( behavior.protocol, "tcp", 3 ) == 0 )
00510         {
00511                 behavior.protocol = "tcp";
00512                 packet.protocol_number = IPPROTO_TCP;
00513                 packet.ip_packet_len += LIBNET_TCP_H;
00514         }
00515         else if ( strncmp( behavior.protocol, "icm", 3 ) == 0 )
00516         {
00517                 behavior.protocol = "icmp";
00518                 packet.protocol_number = IPPROTO_ICMP;
00519                 behavior.filter_text = "( icmp[12:2] == %d ) or ( host %s and icmp[0] == 0 )";
00520                 packet.ip_packet_len += LIBNET_ICMPV4_ECHO_H;
00521         }
00522         else
00523         {
00524                 printf("error: invalid protocol specified with -p\n");
00525                 usage( );
00526                 tixe ( tixe_cleanup, 1 );
00527         }
00528 
00529         if ( packet.dst_port <= 0 || packet.dst_port > 65535 )
00530         {
00531                 printf("error: illegal destination port specified with -d\n");
00532                 usage( );
00533                 tixe ( tixe_cleanup, 1 );
00534         }
00535 
00536         if ( packet.src_port <= 0 || packet.dst_port > 65535 )
00537         {
00538                 printf("error: illegal source port specified with -s\n");
00539                 usage( );
00540                 tixe ( tixe_cleanup, 1 );
00541         }
00542 
00543         if ( behavior.max_ttl <= 0 )
00544         {
00545                 printf("error: illegal maximum time to live value specified with -m\n");
00546                 usage( );
00547                 tixe ( tixe_cleanup, 1 );
00548         } else if ( behavior.max_ttl > 256 ) {
00549                 printf("warning: using an unusually high max ttl value\n");
00550         }
00551 
00552         if ( behavior.min_ttl <= 0 )
00553         {
00554                 printf("error: illegal minimum time to live value specified with -n\n");
00555                 behavior.min_ttl = 1;
00556         } else if ( behavior.min_ttl > behavior.max_ttl ) {
00557                 printf("error: minimum ttl (-n) must be less than maximum ttl (-m)\n");
00558                 usage( );
00559                 tixe ( tixe_cleanup, 1 );
00560         }
00561 
00562         if ( behavior.max_src_port < behavior.min_src_port )
00563         {
00564                 printf ( "error: maximum src port ( specified with -S )\n" );
00565                 printf ( "\tmust be greater than the minimum src port\n" );
00566                 printf ( "\t( specified with -s or default 10240 )\n" );
00567                 usage( );
00568                 tixe ( tixe_cleanup, 1 );
00569         }
00570 
00571         if ( behavior.wait_timeout <= 0 )
00572         {
00573                 printf("error: illegal timeout specified with -w\n");
00574                 usage( );
00575                 tixe ( tixe_cleanup, 1 );
00576         } else if ( behavior.wait_timeout > 300 ) {
00577                 printf("warning: using and unusually high wait timeout specified with -w\n");
00578         }
00579 
00580         if ( behavior.wait_between_packets < 0 )
00581         {
00582                 printf("error: illegal timeout specified with -z\n");
00583                 usage( );
00584                 tixe ( tixe_cleanup, 1 );
00585         } else if ( behavior.wait_between_packets > 10000 ) {
00586                 printf("warning: using an unusually high wait time between packets\n");
00587         }
00588 
00589         if ( packet.src_port == 0 )
00590         {
00591                 printf("warning: using source port 0\n");
00592         }
00593 
00594         if ( behavior.account_level > TP_ACCOUNT_FULL )
00595         {
00596                 behavior.account_level = TP_ACCOUNT_FULL;
00597         }
00598         else if ( behavior.account_level < TP_ACCOUNT_NONE )
00599         {
00600                 behavior.account_level = TP_ACCOUNT_NONE;
00601         }
00602 
00603         /* there will be no overflows here, thank you. */
00604         if ( strlen ( behavior.filter_text )
00605                         + strlen ( behavior.target )
00606                         + 12 > FILTERSIZE )
00607         {
00608                 printf ( "error: bpf filter size limit exceeded.  "
00609                         "Specify a shorter target name (perhaps the ip address).\n" );
00610                 tixe ( tixe_cleanup, 1 );
00611         }
00612 
00613         /*
00614          * Explicitly turn off continuous_accounting with the curses
00615          * It won't work well and is redundant.
00616          */
00617         if ( behavior.output_style == TP_CURSES_OUTPUT )
00618                 behavior.continuous_accounting = NO;
00619 
00620         /*
00621          * note that the default payload is 12 bytes due to a udp
00622          * peculiarity.  less than 12 bytes and no udp response
00623          * is returned.  Don't know if its the stack, libnet, pcap
00624          * or something else completely.
00625          */
00626         if ( behavior.payload_size != 0 )
00627         {
00628                 if ( behavior.payload_size > 8192 )
00629                 {
00630                         printf ( "illegal payload size\n" );
00631                         usage ( );
00632                         tixe ( tixe_cleanup, 1 );
00633                 }
00634                 packet.payload = ( u_char * ) malloc ( behavior.payload_size );
00635                 assert(packet.payload != NULL);
00636                 if ( packet.payload == NULL )
00637                 {
00638                         printf ( "error allocating payload memory for payload\n" );
00639                         tixe ( tixe_cleanup, 1 );
00640                 }
00641                 tixe_cleanup.payload_free = YES;
00642                 memset ( packet.payload, '\0', behavior.payload_size );
00643 
00644                 packet.ip_packet_len += behavior.payload_size;
00645         }
00646 
00647 /*
00648  * Setup the free list for the packet alignment func
00649  */
00650         tp_align_freelist.next = ( struct tp_align_ref * ) malloc ( sizeof ( struct tp_align_ref ) );
00651         if ( tp_align_freelist.next == NULL )
00652         {
00653                 printf ( "error allocating memory for the free list\n" );
00654                 tixe (  tixe_cleanup, 1 );
00655         }
00656         tixe_cleanup.free_list_free = YES;
00657 
00658 
00659 /*
00660  * DNS stuff
00661  */
00662 #ifdef HAVE_GETADDRINFO
00663         /* Use address family independent resolver function, so we can start 
00664            to handle IPv6 as well */
00665         behavior.hint.ai_flags = 0;
00666         behavior.hint.ai_family = PF_UNSPEC;
00667         behavior.hint.ai_socktype = SOCK_STREAM;
00668         behavior.hint.ai_protocol = IPPROTO_IP;
00669         behavior.hint.ai_addrlen = 0;
00670         behavior.hint.ai_addr = NULL;
00671         behavior.hint.ai_canonname = NULL;
00672         behavior.hint.ai_next = NULL;
00673         behavior.target_addrinfo_list_start = NULL;
00674 
00675         if ( (i = getaddrinfo( behavior.target, NULL, &behavior.hint, &behavior.target_addrinfo_list_start )) != 0 ) {
00676                 printf ( "error resolving target address %s: %s\n", behavior.target, gai_strerror(i));
00677                 tixe ( tixe_cleanup, 1 );
00678         }
00679         /* moving this after the getaddrinfo call to fix a segfault on freebsd when the target is invalid */
00680         tixe_cleanup.addrinfo_cleanup = YES;
00681 
00682         /* We should really think about what the proper way for traceproto of
00683            dealing with multiple DNS entries is.
00684            For now, we just pick the first IPv4 address, if any, in the list.
00685 
00686            FIXME: This is too simplistic: we lose the pointer to the start of
00687            the list, so we lose the chance to clean up after ourselves with
00688            freeaddrinfo(3).
00689          */
00690         behavior.target_addrinfo = behavior.target_addrinfo_list_start;
00691         while ( (behavior.target_addrinfo->ai_addr->sa_family != AF_INET) &&
00692                 (behavior.target_addrinfo->ai_next != NULL) ) {
00693                 behavior.target_addrinfo = behavior.target_addrinfo->ai_next;
00694         }
00695 
00696 # ifdef DEBUG
00697         fprintf ( stderr, "resolving %s: success\n", behavior.target );
00698 # endif
00699 
00700         if ( behavior.target_addrinfo->ai_addr->sa_family == AF_INET ) {
00701 # ifdef DEBUG
00702                 fprintf ( stderr, "Address family: AF_INET\n" );
00703 # endif
00704                 l = sizeof(struct sockaddr_in);
00705         } else if ( behavior.target_addrinfo->ai_addr->sa_family == AF_INET6 ) {
00706 # ifdef DEBUG
00707                 fprintf ( stderr, "Address family: AF_INET6\n" );
00708 # endif
00709                 l = sizeof(struct sockaddr_in6);
00710         } else {
00711                 fprintf ( stderr, "Address family %d not supported\n", behavior.target_addrinfo->ai_addr->sa_family );
00712                 l = 0; /* gets rid of a stupid compiler warning --skippy */
00713                 tixe ( tixe_cleanup, 1 );
00714         }
00715         behavior.target_reverse = malloc( NI_MAXHOST );
00716         assert(behavior.target_reverse != NULL);
00717         if ( (i = getnameinfo( behavior.target_addrinfo->ai_addr, l, behavior.target_reverse, NI_MAXHOST-1, NULL, 0, NI_NUMERICHOST )) != 0 ) {
00718                 fprintf ( stderr, "getnameinfo(...) failed: %s\n", gai_strerror(i) );
00719         }
00720 
00721         /* Sorry, this is it so far for IPv6 */
00722         if ( behavior.target_addrinfo->ai_addr->sa_family != AF_INET ) {
00723                 fprintf ( stderr, "Sorry, target address %s did not resolve to an IPv4 address (address family is %d)\n", behavior.target, behavior.target_addrinfo->ai_addr->sa_family );
00724                 tixe ( tixe_cleanup, 1 );
00725         }
00726 #else
00727         /* IPv4 specific implementation */
00728         behavior.packed_target_reverse = gethostbyname ( behavior.target );
00729         if ( behavior.packed_target_reverse == NULL )
00730         {
00731                 printf ( "error resolving target address %s\n", behavior.target );
00732                 tixe ( tixe_cleanup, 1 );
00733         }
00734 
00735         behavior.target_reverse = inet_ntoa (
00736                         *(struct in_addr *)( behavior.packed_target_reverse->h_addr_list[0]));
00737 #endif /* HAVE_GETADDRINFO */
00738 
00739 
00740 /*
00741  * initialize the skips list
00742  */
00743         if ( behavior.do_skip == YES && parse_skips ( behavior.skip_str ) != 0 )
00744         {
00745                 fprintf ( stderr, "error with option k arguments\n" );
00746                 usage ( );
00747                 tixe ( tixe_cleanup, 1 );
00748         }
00749 
00750 /*
00751  * set up accounting
00752  */
00753         state.account_hops = behavior.max_ttl + 1;
00754         state.hop_record = ( struct hop_record * ) calloc (
00755                                                 state.account_hops,
00756                                                 sizeof ( struct hop_record ) );
00757         if ( state.hop_record == NULL )
00758         {
00759                 perror ( "memory allocation error" );
00760                 tixe ( tixe_cleanup, 1 );
00761         }
00762         tixe_cleanup.hop_record_free = YES;
00763 
00764 /*
00765  * find interface if needed and start packet
00766  */
00767         /* find_interface ( ); */
00768 
00769 #ifdef OS_FREEBSD
00770         /*
00771          * temporary kludge: freebsd (and probably others) dump core
00772          * when calling pcap_open_live with a first arguement (the interface)
00773          * as NULL.  This causes it to revert to the interface "any" on
00774          * FreeBSD.  The "any" interface doesn't exist, but at least it
00775          * errors out rather than dumping core.
00776          */
00777         behavior.default_if = NO;
00778 #endif /* OS_FREEBSD */
00779 
00780         if ( debug.interface == YES )
00781         {
00782                 printf ( "debug: using default interface = %s\n",
00783                         behavior.default_if ? "YES"  : "NO" );
00784                 printf ( "debug: interface flag is %s\n",
00785                         behavior.default_if == NO ? behavior.interface : "NULL" );
00786                 
00787         }
00788 
00789         state.packet = libnet_init (
00790                 LIBNET_RAW4,        /* inject type */
00791         /*      NULL,   */         /* device */
00792                 behavior.default_if == NO ? behavior.interface : NULL,
00793                 ( char * ) state.error_buff );
00794         if (!state.packet)
00795         {
00796                 printf("Error: %s\n", * state.error_buff);
00797                 tixe ( tixe_cleanup, 1 );
00798         }
00799         tixe_cleanup.libnet_cleanup = YES;
00800 
00801         packet.packed_target = libnet_name2addr4(
00802                 state.packet, behavior.target, LIBNET_RESOLVE );
00803         if ( packet.packed_target == -1 )
00804         {
00805                 printf("error resolving destination (%s): %s\n",
00806                         behavior.target, libnet_geterror( state.packet ) );
00807                 usage( );
00808                 tixe ( tixe_cleanup, 1 );
00809         }
00810 
00811         packet.packed_src = libnet_get_ipaddr4( state.packet );
00812         if ( packet.packed_src == -1 )
00813         {
00814                 printf("error resolving source: %s\n",
00815                         libnet_geterror( state.packet ) );
00816                 tixe ( tixe_cleanup, 1 );
00817         }
00818 
00819         libnet_seed_prand( state.packet );
00820 
00821 /*
00822  * do the pcap stuff and the initial filter
00823  */
00824         /* state.psocket = pcap_open_live( NULL, */
00825         /* state.psocket = pcap_open_live( behavior.interface, */
00826         state.psocket = pcap_open_live (
00827                                 behavior.default_if == NO ? behavior.interface : NULL,
00828                                 SNAPLEN,
00829                                 NO_PROMISC,
00830                                 ( behavior.wait_timeout * 1000 ),
00831                                 state.pc_error );
00832         if ( state.psocket == NULL )
00833         {
00834                 printf("pcap error: %s\n", state.pc_error);
00835                 tixe ( tixe_cleanup, 1 );
00836         }
00837         tixe_cleanup.pcap_cleanup = YES;
00838 
00839         /*
00840          * this is a specific weirdness.  See the README for more details.
00841          *
00842          * The pcap_fileno is a bit borrowed from Michael Toren
00843          * and his tcptraceroute.  Appearently the pcap documentation
00844          * is blatently wrong here and the pcap_fileno actually returns
00845          * the socket fd, not the fd of the logfile.
00846          *
00847          * So now you have a choice.  You can use my crude kludge to
00848          * break the encapsulation, or you can use the "legit" but
00849          * badly mis-documented library function....see the configure
00850          * options.
00851          */
00852 #ifdef USE_PCAP_FILENO
00853         state.fake_psocket = ( struct fake_pcap * )
00854                 malloc ( sizeof ( struct fake_pcap ) );
00855         if ( state.fake_psocket == NULL )
00856         {
00857                 printf ( "error allocating pcap_fileno memory\n" );
00858                 tixe ( tixe_cleanup, 1 );
00859         }
00860         tixe_cleanup.fake_psocket_free = YES;
00861 
00862         state.fake_psocket->fd  = pcap_fileno ( state.psocket );
00863 #else
00864         state.fake_psocket = ( struct fake_pcap * ) state.psocket;
00865 #endif /* USE_PCAP_FILENO */
00866 
00867 #ifdef OS_FREEBSD
00868         /*
00869          * Appearently, BSD bpf fds won't return immediately without this
00870          * set.  Without it, select waits until its timeout and THEN
00871          * grabs and parses the packet.  Poof, instant round trip times
00872          * of whatever -w is set to.
00873          */
00874         if ( ioctl ( state.fake_psocket->fd, BIOCIMMEDIATE, & on ) > 0 )
00875         {
00876                 printf ( "error setting BSD BPF fd to immediate\n" );
00877                 tixe ( tixe_cleanup, 1 );
00878         }
00879 #endif /* OS_FREEBSD */
00880 
00881 /*
00882  * set up the initial filter
00883  */
00884         if ( do_filter() != 0 )
00885         {
00886                 tixe ( tixe_cleanup, 1 );
00887         }
00888 
00889 /*
00890  * drop the root privileges if possible
00891  */
00892         if ( setuid ( getuid ( ) ) != 0 )
00893         {
00894                 printf ( "error dropping privileges\n" );
00895                 tixe ( tixe_cleanup, 1 );
00896         }
00897         if ( setgid ( getgid ( ) ) != 0 )
00898         {
00899                 printf ( "error dropping privileges\n" );
00900                 tixe ( tixe_cleanup, 1 );
00901         }
00902 
00903 /*
00904  * if we're doing as_discovery, set it up here
00905  */
00906         if ( behavior.as_discovery == YES && setup_as ( ) != 0 )
00907         {
00908                 printf ( "error doing AS discovery: %s\n", as_string );
00909                 behavior.as_discovery = NO;
00910         }
00911 
00912 /*
00913  * set up the signals
00914  */
00915         signal ( SIGINT, ctrl_c );
00916         signal ( SIGTSTP, ctrl_z );
00917 
00918 /*
00919  * ttl setup depending on if we're tracing forward or backwards
00920  */
00921         if ( behavior.hop_incr_unit == 1 )
00922                 state.current_hop = behavior.min_ttl;
00923         else
00924                 state.current_hop = behavior.max_ttl;
00925 /*
00926  * MAIN LOOP STARTS HERE
00927  *
00928  * loop through, building the ip
00929  * and sending it
00930  */
00931         behavior.report( TP_OUT_HEADER, NULL, 0 );
00932 
00933 
00934         /*
00935          * conditional: ( A && B ) || C
00936          */
00937         for ( state.packets_this_hop = 0;
00938 
00939                 ( state.current_hop >= behavior.min_ttl
00940                 &&
00941                 state.current_hop <= behavior.max_ttl )
00942                 ||
00943                 state.packets_this_hop < behavior.packets_per_hop;
00944 
00945                 ++( state.packets_this_hop ) )
00946         {
00947                 /*
00948                  * reset if we've sent enough probes for this ttl
00949                  */
00950                 if ( state.packets_this_hop >= behavior.packets_per_hop )
00951                 {
00952                         state.current_hop += behavior.hop_incr_unit;
00953                         state.packets_this_hop = 0;
00954                 }
00955 
00956                 /*
00957                  * skip the hops marked on the cmd line
00958                  */
00959                 if ( behavior.do_skip == YES && behavior.skips[ state.current_hop ] == YES )
00960                 {
00961                         state.current_hop += behavior.hop_incr_unit;
00962                         state.packets_this_hop = -1;
00963                         continue;
00964                 }
00965 
00966                 state.packet_match = TP_PACKET_NO;
00967                 state.low_ttl = NO;
00968 
00969 /*
00970  * increment the src and/or dst ports
00971  */
00972                 packet.src_port += behavior.src_port_incr;
00973                 packet.dst_port += behavior.dst_port_incr;
00974 
00975                 build_packet();
00976 
00977 /*
00978  * build the ip
00979  * ( this should probably be rolled in build_packet() )
00980  */
00981                 packet.ip_id = libnet_get_prand(LIBNET_PRu16);
00982                 if ( debug.packet_length == YES )
00983                         printf ( "debug: packet.ip_id=%d", packet.ip_id );
00984 
00985                 state.ip_h = libnet_build_ipv4(
00986                         packet.ip_packet_len,   /* IP packet len */
00987                         0,                                              /* tos */
00988                         packet.ip_id,                   /* frag id */
00989                         packet.frag_bit,                /* frag offset */
00990                         state.current_hop,              /* ttl */
00991                         packet.protocol_number,
00992                         0,                                              /* checksum */
00993                         packet.packed_src,              /* packed source */
00994                         packet.packed_target,           /* packed target */
00995                         NULL,                                   /* payload */
00996                         0,                                              /* payload size */
00997                         state.packet,
00998                         state.ip_h );
00999 
01000                 if ( debug.packet_length == YES )
01001                         printf ( "\nHEADER_LENGTH IP:%d payload:%d, total:%d\n",
01002                                 LIBNET_IPV4_H, behavior.payload_size, packet.ip_packet_len );
01003 
01004                 if ( debug.send_buf == YES )
01005                 {
01006                         printf ( "debug: send buffer:\n" );
01007                         debug_packet ( libnet_getpbuf ( state.packet, state.ip_h ),
01008                                   libnet_getpbuf_size ( state.packet, state.ip_h ) );
01009                         debug_packet ( libnet_getpbuf ( state.packet, state.tcp_h ),
01010                                   libnet_getpbuf_size ( state.packet, state.tcp_h ) );
01011                         debug_packet ( packet.payload, behavior.payload_size );
01012                 }
01013 /*
01014  * and change the filter
01015  */
01016                 if ( do_filter() != 0 )
01017                 {
01018                         tixe ( tixe_cleanup, 1 );
01019                 }
01020 
01021 /*
01022  * spit out the hop number if this is the first probe this hop
01023  * then start timer and send the packet
01024  */
01025                 if ( state.packets_this_hop == 0 )
01026                         behavior.report( TP_OUT_HOP_NUMBER, ( struct in_addr * ) NULL, 0 );
01027 
01028                 gettimeofday ( & state.start_time, NULL );
01029 
01030                 if ( debug.loop == YES ) { printf ( "debug: time checked, writing packet\n" ); }
01031 
01032                 if ( libnet_write( state.packet ) == -1 )
01033                 {
01034                         printf("error at send: %s\n",
01035                                 libnet_geterror( state.packet ) );
01036                         tixe ( tixe_cleanup, 1 );
01037                 }
01038 
01039                 if ( debug.loop == YES ) { printf ( "debug: packet written, waiting\n" ); }
01040 
01041 /*
01042  * wait for a packet to get
01043  * through the filter, timeout
01044  * after the wait_timeout
01045  */
01046                 while ( state.packet_match == TP_PACKET_NO )
01047                 {
01048                         state.packet_wait.tv_sec  = behavior.wait_timeout;
01049                         state.packet_wait.tv_usec = 0;
01050                         FD_ZERO( & ( state.wheel ) );
01051                         FD_SET( state.fake_psocket->fd, & ( state.wheel ) );
01052 
01053                         if ( debug.loop == YES ) { printf ( "debug: select\n" ); }
01054 
01055                         if ( select( ( state.fake_psocket->fd ) + 1,
01056                                         & ( state.wheel ),
01057                                         NULL,
01058                                         NULL,
01059                                         & state.packet_wait ) > 0 )
01060                         {
01061                                 /*
01062                                  * if we get a bite, note the time,
01063                                  * test the response, and report it if OK
01064                                  */
01065                                 gettimeofday ( & ( state.end_time ), NULL );
01066 
01067                                 if ( debug.loop == YES )
01068                                         printf ( "debug: select returned, capturing\n" );
01069 
01070                                 strcpy ( state.pc_error, "unknown" );
01071 
01072                                 /*
01073                                  * If we've gotten here, it means that the select returned > 0
01074                                  * meaning that there's a packet waiting for us.
01075                                  */
01076                                 state.capture_buf = pcap_next(
01077                                                 state.psocket,
01078                                                 & ( state.psock_hdr ) );
01079                                 /*
01080                                  * Under certain conditions, pcap_next returns NULL ( meaning no packet )
01081                                  * even though the select returned > 0.
01082                                  * This if is a somewhat heavy handed workaround while sorting this out.
01083                                  * Effectively if pcap_next returns NULL, try again and only error if we
01084                                  * get NULL a second time.  The second pacp_next seems to see the packet 
01085                                  * consistantly.
01086                                  */
01087                                 if ( state.capture_buf == NULL )
01088                                 {
01089                                         state.capture_buf = pcap_next(
01090                                                 state.psocket,
01091                                                 & ( state.psock_hdr ) );
01092 
01093                                         if ( state.capture_buf == NULL )
01094                                         {
01095                                                 printf ( "error receiving packet: %s\n",
01096                                                         state.pc_error );
01097                                                 tixe ( tixe_cleanup, 1 );
01098                                         }
01099                                 }
01100 
01101                                 if ( debug.loop == YES )
01102                                         printf ( "debug: captured, parsing\n" );
01103 
01104                                 state.trip_time = diff_time (
01105                                         & ( state.start_time ),
01106                                         & ( state.end_time ) );
01107 
01108                                 if ( parse_packet( state.capture_buf ) > 0 )
01109                                 {
01110                                         freelist_cleaner ( );
01111                                 }
01112 
01113                                 if ( debug.loop == YES )
01114                                         printf ( "debug: parsed, resets\n" );
01115 
01116                                 if ( packet.protocol_number == IPPROTO_TCP
01117                                         && behavior.tcp_resets == YES
01118                                         && state.packet_match == TP_PACKET_DONE )
01119                                 {
01120                                         if ( send_tcp_reset ( ) != 0 )
01121                                                 printf("error at send: %s\n",
01122                                                         libnet_geterror( state.packet ) );
01123                                 }
01124 
01125                                 /* blank the buffer to prevent confusion */
01126                                 memset ( (char *) state.capture_buf, '\0', sizeof ( state.capture_buf ) );
01127                                 state.trip_time = ( double ) 0.0;
01128                         } else {
01129                                 /*
01130                                  * if we get here,  no one wanted to talk to us for this probe
01131                                  */
01132                                 account_packet ( ( double ) 0 );
01133                                 behavior.report( TP_OUT_HOP_INFO, ( struct in_addr * ) NULL, TP_TYPE_NR );
01134                                 state.packet_match = TP_PACKET_TIMEOUT;
01135 
01136                                 if ( debug.loop == YES )
01137                                         printf ( "debug: no answer (%d)\n", FD_ISSET ( state.fake_psocket->fd, & ( state.wheel ) ) );
01138                         }
01139 
01140                         /*
01141                          * if there was an interupt during the wait
01142                          */
01143                         if ( behavior.do_audit == YES || behavior.do_audit_exit == YES )
01144                         {
01145                                 if ( behavior.do_audit_exit == YES )
01146                                         behavior.report( TP_OUT_FOOTER, NULL, 0 );
01147                                 else
01148                                         hop_audit();
01149                         }
01150                 } /* end of while ( packet_match == TP_PACKET_NO ) loop */
01151 
01152 /*
01153  * an acceptable response in hand,
01154  * quit and clean up, or start over
01155  */
01156                 /*
01157                  * in technical terms, this is "icky"
01158                  * it does however, seem to operate correctly
01159                  *
01160                  * conditional: ( ( A || B ) && C && D ) || ( E && F && G )
01161                  * I told you it was icky...
01162                  */
01163                 if ( ( ( state.target_response == YES
01164                                         ||
01165                                         state.current_hop == behavior.max_ttl )
01166                                 &&
01167                                 state.packets_this_hop >= behavior.packets_per_hop - 1
01168                                 &&
01169                                 behavior.hop_incr_unit == 1 )
01170                         ||
01171                         ( behavior.hop_incr_unit == -1
01172                                 &&
01173                                 state.current_hop == behavior.min_ttl
01174                                 &&
01175                                 state.packets_this_hop >= behavior.packets_per_hop - 1 ) )
01176                 {
01177                         /*
01178                          * If we get here, we're at the end of a run
01179                          * either with one or more responses from the target
01180                          * or because we've reached the ttl limit.
01181                          */
01182                         state.current_hop = behavior.max_ttl + 1;
01183 
01184                         /*
01185                          * if we're supposed to be continuous,
01186                          * reset the loop and start again
01187                          */
01188                         if ( state.continuous_count != (int) NULL )
01189                         {
01190                                 state.continuous_count--;
01191                                 if ( state.continuous_count == 0 )
01192                                         behavior.continuous = NO;
01193                         }
01194                         if ( behavior.continuous == YES )
01195                         {
01196                                 state.packet_match = TP_PACKET_NO;
01197                                 state.target_response = NO;
01198 
01199                                 if ( behavior.hop_incr_unit == 1 )
01200                                         state.current_hop = behavior.min_ttl;
01201                                 else
01202                                         state.current_hop = behavior.max_ttl;
01203 
01204                                 /*
01205                                  * setting packets_this_hop to -1 allows the
01206                                  * reset if at the beginning of the loop to function
01207                                  */
01208                                 state.packets_this_hop = -1;
01209 
01210                                 if ( behavior.continuous_accounting == YES )
01211                                         hop_audit();
01212                         }
01213                 }
01214 
01215                 /*
01216                  * after a run pause for -W usecs
01217                  * (at least I think it usecs)
01218                  */
01219                 if ( behavior.wait_between_packets != 0 )
01220                         usleep ( behavior.wait_between_packets * 1000 );
01221 
01222 /*
01223  * reset the ports as needed
01224  */
01225                 if ( packet.src_port >= behavior.max_src_port && behavior.src_port_incr == 1 )
01226                         packet.src_port = behavior.min_src_port - 1;
01227                 else if ( packet.src_port <= behavior.min_src_port && behavior.src_port_incr == -1 )
01228                         packet.src_port = behavior.max_src_port + 1;
01229 
01230                 if ( packet.dst_port >= behavior.max_dst_port && behavior.dst_port_incr == 1)
01231                         packet.dst_port = behavior.min_dst_port - 1;
01232                 else if ( packet.dst_port <= behavior.min_dst_port && behavior.dst_port_incr == -1)
01233                         packet.dst_port = behavior.max_dst_port + 1;
01234 
01235                 if ( debug.loop == YES ) { printf ( "debug, looping back to the beginning\n" ); }
01236 
01237         } /* end of the main send/recv loop */
01238 
01239 /*
01240  * yahoo, we're done
01241  * 
01242  * spit out the stats, sweep up after ourselves, and close up shop
01243  * last packet out please shut off the lights
01244  */
01245         behavior.report ( TP_OUT_FOOTER, NULL, 0 );
01246         /* hop_audit(); */
01247 
01248         tixe ( tixe_cleanup, 0 );       /* cleanup and exit, status 0 */
01249 
01250         exit ( 0 ); /* we should never get here */
01251 }
01252 

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