tp_miscfunc.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 #include <assert.h>
00036 
00037 #include "tp_miscfunc.h"
00038 #include "traceproto.h"
00039 #include "config.h"
00040 #include "tp_as.h"
00041 
00042 #ifdef HAVE_LIBCAP
00043 # include <sys/capability.h>
00044 #endif /* HAVE_LIBCAP */
00045 
00046 /*
00047 #ifdef HAVE_LIBCURSES
00048 #include <curses.h>
00049 #endif / * HAVE_LIBCURSES */
00050 
00051 #ifdef HAVE_LIBDMALLOC
00052 #include <dmalloc.h>
00053 #endif /* HAVE_LIBDMALLOC */
00054 
00055 /*
00056  * take a comma separated list (sans spaces) and give them a miss
00057  * (ie don't send probes with the ttl set to these numbers)
00058  */
00059 int parse_skips ( char * skip_ptr )
00060 {
00061         size_t c;
00062         char tmp[ 4 ];
00063         int tmp_c = 0;
00064 
00065         behavior.skips = ( int * ) calloc ( behavior.max_ttl + 1, sizeof ( int ) );
00066         if ( behavior.skips == NULL )
00067         {
00068                 printf ( "memory allocation error" );
00069                 tixe ( tixe_cleanup, 1 );
00070         }
00071 
00072         tixe_cleanup.skips_free = YES;
00073 
00074         /*
00075          * loop through the str from the cmd line
00076          * if its a digit remember it
00077          * if its a comma, add it to the list of skipped hops
00078          */
00079         memset ( & tmp, '\0', sizeof ( tmp ) );
00080         for ( c = 0; c < strlen ( skip_ptr ); c++ )
00081         {
00082                 if ( isdigit ( skip_ptr[ c ] ) && tmp_c < 4 )
00083                 {
00084                         tmp[ tmp_c++ ] = skip_ptr[ c ];
00085                 }
00086                 else if ( isdigit ( skip_ptr[ c ] ) && tmp_c >= 4 )
00087                 {
00088                         return 1;
00089                 }
00090                 else if ( skip_ptr[ c ] == ',' )
00091                 {
00092                         tmp_c = atoi ( tmp );
00093                         if ( tmp_c > 0 && tmp_c <= behavior.max_ttl )
00094                         {
00095                                 behavior.skips[ tmp_c ] = 1;
00096                         }
00097                         else
00098                         {
00099                                 return 1;
00100                         }
00101                         tmp_c = 0;
00102                         memset ( & tmp, '\0', sizeof ( tmp ) );
00103                 }
00104                 else
00105                 {
00106                         return 1;
00107                 }
00108         } /* end of for loop */
00109 
00110         /* one more time so it doesn't require a trailing comma */
00111         if ( tmp_c != 0 )
00112         {
00113                 tmp_c = atoi ( tmp );
00114                 if ( tmp_c > 0 && tmp_c <= behavior.max_ttl )
00115                 {
00116                         behavior.skips[ tmp_c ] = 1;
00117                 }
00118                 else
00119                 {
00120                         return 1;
00121                 }
00122                 tmp_c = 0;
00123                 memset ( & tmp, '\0', sizeof ( tmp ) );
00124         }
00125 
00126         return 0;
00127 }
00128 
00129 /*
00130  * remember if the user hits it
00131  */
00132 void ctrl_c ( __attribute__((__unused__)) int unused )
00133 {
00134         behavior.do_audit_exit = YES;
00135 }
00136 void ctrl_z( __attribute__((__unused__)) int unused )
00137 {
00138         behavior.do_audit = YES;
00139 }
00140 
00141 /*
00142  * one timeval - another timeval
00143  */
00144 double diff_time ( struct timeval * start, struct timeval * end )
00145 {
00146         register double diff;
00147 
00148         diff = ( double )( end->tv_sec  - start->tv_sec  ) * 1000.0
00149              + ( double )( end->tv_usec - start->tv_usec ) / 1000.0;
00150 
00151         return diff;
00152 }
00153 
00154 /*
00155  * create and apply the Berkley Packet Filter filter
00156  */
00157 int do_filter( void )
00158 {
00159         char filter [ FILTERSIZE ];
00160         struct bpf_program compiled_filter;
00161         bpf_u_int32 netmask = 0;
00162 
00163         if ( packet.protocol_number == IPPROTO_ICMP )
00164         {
00165                 sprintf ( filter,                       /* the buffer fed to pcap */
00166                         behavior.filter_text,   /* the static text set on traceproto.c */
00167                         packet.ip_id,                   /* the randomly generated id */
00168                         behavior.target );
00169         } else {
00170                 sprintf ( filter,                       /* the buffer fed to pcap */
00171                         behavior.filter_text,   /* the static text set on traceproto.c */
00172                         behavior.target,
00173                         packet.src_port,
00174                         packet.dst_port,
00175                         packet.ip_id );                 /* the randomly generated id */
00176         }
00177 
00178         if ( debug.interface == YES )
00179                 printf ( "debug: BPF filter: %s\n",
00180                         filter );
00181 
00182         if ( pcap_compile(
00183                 state.psocket,           /* pcap_t */
00184                 & compiled_filter,
00185                 filter,
00186                 0,                      /* don't optimise */
00187                 netmask ) == -1 )
00188         {
00189                 printf("pcap error: %s\n", pcap_geterr( state.psocket ) );
00190                 return 1;
00191         }
00192 
00193         if ( pcap_setfilter(
00194                 state.psocket,
00195                 & compiled_filter ) != 0 )
00196         {
00197                 printf("pcap error: %s\n", pcap_geterr( state.psocket ) );
00198                 return 1;
00199         }
00200 
00201         pcap_freecode ( & compiled_filter );
00202 
00203         return 0;
00204 }
00205 
00206 /*
00207  * shove the details into memory
00208  */
00209 int account_packet ( double return_time )
00210 {
00211 
00212 /*
00213  * record total for all hops
00214  */
00215         if ( return_time == ( double ) 0 )
00216                 state.hop_record[ 0 ].lost_packets++;
00217         else
00218                 state.hop_record[ 0 ].num_packets++;
00219 
00220         if ( state.hop_record[ 0 ].min_time == ( double ) 0
00221                         || state.hop_record[ 0 ].min_time > return_time )
00222                 state.hop_record[ 0 ].min_time = return_time;
00223 
00224         if ( state.hop_record[ 0 ].max_time < return_time )
00225                 state.hop_record[ 0 ].max_time = return_time;
00226 
00227         state.hop_record[ 0 ].ave_time =
00228                       ( state.hop_record[ 0 ].ave_time
00229                 *       state.hop_record[ 0 ].num_packets
00230                 +       return_time )
00231                 /     ( state.hop_record[ 0 ].num_packets
00232                 +       1 );
00233 
00234 /*
00235  * record the individual hop stats
00236  */
00237         state.hop_record[ state.current_hop ].distance = state.current_hop;
00238 
00239         /*
00240          * if there was no response, record the lost packet, but not the time
00241          */
00242         if ( return_time == ( double ) 0 )
00243         {
00244                 state.hop_record[ state.current_hop ].lost_packets++;
00245                 return 0;
00246         }
00247         else
00248                 state.hop_record[ state.current_hop ].num_packets++;
00249 
00250         if ( state.hop_record[ state.current_hop ].min_time == (double)0
00251                 || state.hop_record[ state.current_hop ].min_time > return_time )
00252         {
00253                 state.hop_record[ state.current_hop ].min_time = return_time;
00254         }
00255 
00256         if ( state.hop_record[ state.current_hop ].max_time < return_time )
00257                 state.hop_record[ state.current_hop ].max_time = return_time;
00258 
00259         /*
00260          * math: ave = ( ave * (#pkts - 1) + response ) / #pkts
00261          */
00262         state.hop_record[ state.current_hop ].ave_time =
00263                         ( state.hop_record[ state.current_hop ].ave_time
00264                 *       ( state.hop_record[ state.current_hop ].num_packets
00265                 -         1 )
00266                 +         return_time )
00267                 /       ( state.hop_record[ state.current_hop ].num_packets );
00268 
00269         return 1;
00270 }
00271 
00272 /*
00273  * formal info on all packets seen so far
00274  * ( may or may not indicate the end of the run )
00275  */
00276 void hop_audit( void )
00277 {
00278         int hop;
00279 
00280         if ( behavior.account_level > TP_ACCOUNT_NONE )
00281         {
00282                 printf ( "\nhop :  min   /  ave   /  max   :  # packets  :  # lost\n" );
00283         }
00284 
00285         if ( behavior.account_level == TP_ACCOUNT_FULL )
00286         {
00287                 printf (     "-------------------------------------------------------\n" );
00288                 for ( hop = behavior.min_ttl; hop <= behavior.max_ttl; hop++ )
00289                 {
00290                         if ( state.hop_record[ hop ].num_packets != 0
00291                                 || state.hop_record[ hop ].lost_packets != 0 )
00292                         {
00293                                 printf ( "%3d : %#.5g / %#.5g / %#.5g : %3d packets : %3d lost\n",
00294                                         hop,
00295                                         state.hop_record[ hop ].min_time,
00296                                         state.hop_record[ hop ].ave_time,
00297                                         state.hop_record[ hop ].max_time,
00298                                         state.hop_record[ hop ].num_packets,
00299                                         state.hop_record[ hop ].lost_packets );
00300                         }
00301 
00302                 } /* end for hop loop */
00303         } /* end if full accounting */
00304 
00305         if ( behavior.account_level > TP_ACCOUNT_NONE )
00306         {
00307                 printf (     "------------------------Total--------------------------\n" );
00308                 if ( state.hop_record[ 0 ].num_packets != 0
00309                         || state.hop_record[ 0 ].lost_packets != 0 )
00310                 {
00311                         printf ( "total %#.5g / %#.5g / %#.5g : %3d packets : %3d lost\n",
00312                                 state.hop_record[ 0 ].min_time,
00313                                 state.hop_record[ 0 ].ave_time,
00314                                 state.hop_record[ 0 ].max_time,
00315                                 state.hop_record[ 0 ].num_packets,
00316                                 state.hop_record[ 0 ].lost_packets );
00317                 }
00318                 printf ( "\n" );
00319         } /* end if ( account level > TP_ACCOUNT_NONE ) */
00320 
00321         if ( behavior.do_audit_exit == YES )
00322         {
00323                 printf ( "\n" );
00324                 tixe ( tixe_cleanup, 0 );
00325         }
00326 
00327         behavior.do_audit = NO;
00328 }
00329 
00330 /*
00331  * take the name used to call and make it canonical
00332  */
00333 int reg_name ( char * arg0 )
00334 {
00335         size_t c;
00336         state.prog = & arg0 [ 0 ];
00337         for ( c = 0; c < strlen ( arg0 ); c++ )
00338         {
00339                 if ( arg0[ c ] == '/' )
00340                 {
00341                         state.prog = & arg0[ c+1 ];
00342                 }
00343         }
00344 
00345         return strlen ( state.prog );
00346 }
00347 
00348 /*
00349  * cleanup our mess and vamoos
00350  */
00351 void tixe ( struct cleanup clean_list, int exit_status )
00352 {
00353         if ( clean_list.payload_free      == YES ) { free ( packet.payload     ); }
00354         if ( clean_list.skips_free        == YES ) { free ( behavior.skips     ); }
00355         if ( clean_list.hop_record_free   == YES ) { free ( state.hop_record   ); }
00356         if ( clean_list.fake_psocket_free == YES ) { free ( state.fake_psocket ); }
00357 
00358         if ( clean_list.libnet_cleanup  == YES ) { libnet_destroy ( state.packet ); }
00359         if ( clean_list.pcap_cleanup    == YES ) { pcap_close ( state.psocket );    }
00360 
00361 #ifdef HAVE_GETADDRINFO
00362         if ( clean_list.addrinfo_cleanup  == YES ) { freeaddrinfo( behavior.target_addrinfo_list_start ); }
00363 #endif /* HAVE_GETADDRINFO */
00364 
00365 /*
00366 #ifdef HAVE_LIBCURSES
00367         if ( clean_list.curses_end == YES )
00368         {
00369                 endwin ( );
00370         }
00371 #endif / * HAVE_LIBCURSES */
00372 
00373 #ifdef HAVE_LIBDMALLOC
00374         /* dmalloc_error(); */
00375 #endif /* HAVE_LIBDMALLOC */
00376 
00377         exit ( exit_status );
00378 }
00379 
00380 /*
00381  * who are we
00382  */
00383 void version( void )
00384 {
00385         printf("%s version %s, released %s\n", PACKAGE, VERSION, RELEASE_DATE );
00386 }
00387 
00388 /*
00389  * sort out which tcp flags to use
00390  * called from the cmd line flags parsing
00391  */
00392 u_char parse_flags ( char * user_flags )
00393 {
00394         int i, errors = 0;
00395         u_char packet_flags = '\0';
00396 
00397         for ( i = strlen ( user_flags ); i > 0; i-- )
00398         {
00399                 switch ( user_flags [ 0 ] )
00400                 {
00401                 case 'S':
00402                 case 's':
00403                         packet_flags |= TH_SYN;
00404                         break;
00405                 case 'A':
00406                 case 'a':
00407                         packet_flags |= TH_ACK;
00408                         break;
00409                 case 'R':
00410                 case 'r':
00411                         packet_flags |= TH_RST;
00412                         break;
00413                 case 'U':
00414                 case 'u':
00415                         packet_flags |= TH_URG;
00416                         break;
00417                 case 'p':
00418                 case 'P':
00419                         packet_flags |= TH_PUSH;
00420                         break;
00421                 case 'F':
00422                 case 'f':
00423                         packet_flags |= TH_FIN;
00424                         break;
00425                 case 'E':
00426                 case 'e':
00427                         packet_flags |= TH_ECE;
00428                         break;
00429                 case 'C':
00430                 case 'c':
00431                         packet_flags |= TH_CWR;
00432                         break;
00433                 default:
00434                         errors++;
00435                         break;
00436                 }
00437                 user_flags++;
00438         }
00439 
00440         return packet_flags;
00441 }
00442 
00443 
00444 /*
00445  * make a human readable timestamp
00446  */
00447 int make_timestamp ( char * str_buf )
00448 {
00449         time_t epoch_time;
00450         struct tm * time_struct;
00451         char time_string [ TP_TIMESTAMP_LEN ];
00452         const char * month [ ] = {
00453                         "Jan", "Feb", "Mar", "Apr",
00454                         "May", "Jun", "Jul", "Aug",
00455                         "Sep", "Oct", "Nov", "Dec" };
00456 
00457         if ( ( epoch_time = time ( NULL ) ) == -1 )
00458         {
00459                 perror ( "error determining time" );
00460                 tixe ( tixe_cleanup, 1 );
00461         }
00462 
00463         time_struct = localtime ( & epoch_time );
00464 
00465         memset ( time_string, '\0', TP_TIMESTAMP_LEN );
00466 
00467         if ( debug.timestamp == YES )
00468                 printf ( "timestamp_style: %d\n", behavior.timestamp_style );
00469 
00470         switch ( behavior.timestamp_style )
00471         {
00472         case TP_TIMESTAMP_US:
00473                 snprintf ( time_string,
00474                         TP_TIMESTAMP_LEN - 1,
00475                         "%d/%0.2d/%d:%d:%d:%d", 
00476                         time_struct->tm_mon + 1,
00477                         time_struct->tm_mday,
00478                         /* time_struct->tm_mon, */
00479                         time_struct->tm_year + 1900,
00480                         time_struct->tm_hour,
00481                         time_struct->tm_min,
00482                         time_struct->tm_sec );
00483                 break;
00484         case TP_TIMESTAMP_DESCEND:
00485                 snprintf ( time_string,
00486                         TP_TIMESTAMP_LEN - 1,
00487                         "%d/%d/%d:%d:%d:%d",
00488                         time_struct->tm_year + 1900,
00489                         time_struct->tm_mon + 1,
00490                         time_struct->tm_mday,
00491                         time_struct->tm_hour,
00492                         time_struct->tm_min,
00493                         time_struct->tm_sec );
00494                 break;
00495         case TP_TIMESTAMP_EPOCH:
00496                 snprintf ( time_string,
00497                         TP_TIMESTAMP_LEN - 1,
00498                         "%d",
00499                         epoch_time );
00500                 break;
00501         case TP_TIMESTAMP_STD:
00502         default:
00503                 snprintf ( time_string,
00504                         TP_TIMESTAMP_LEN - 1,
00505                         "%0.2d/%s/%d:%d:%d:%d", 
00506                         time_struct->tm_mday,
00507                         month [ time_struct->tm_mon ],
00508                         /* time_struct->tm_mon, */
00509                         time_struct->tm_year + 1900,
00510                         time_struct->tm_hour,
00511                         time_struct->tm_min,
00512                         time_struct->tm_sec );
00513                 break;
00514         }
00515 
00516         strncpy ( str_buf, time_string, TP_TIMESTAMP_LEN );
00517 
00518         return strlen ( time_string );
00519 }
00520 
00521 /*
00522  * function to align the buffers on machines that need aligned buffers
00523  */
00524 u_char * tp_align ( const u_char * buf, unsigned int offset, unsigned int size )
00525 {
00526         unsigned char * new_buf;
00527         struct tp_align_ref * new_ref;
00528         struct tp_align_ref * ref_ptr;
00529 
00530         new_buf = ( u_char * ) malloc ( size );
00531         assert(new_buf != NULL);
00532 
00533         /* paranioa check in case the buf is NULL, shouldn't ever happen */
00534         if ( buf == NULL )
00535         {
00536                 printf ( "error: reading from empty receive buffer\n" );
00537                 tixe ( tixe_cleanup, 1 );
00538         }
00539 
00540         memset ( new_buf, '\0', size );
00541         memcpy ( new_buf, buf + offset, size );
00542 
00543         new_ref = ( struct tp_align_ref * ) malloc ( sizeof ( struct tp_align_ref ) );
00544         assert(new_ref != NULL);
00545         new_ref->next = NULL;
00546         new_ref->ref = new_buf;
00547         for (   ref_ptr = & tp_align_freelist;
00548                 ref_ptr->next != NULL;
00549                 ref_ptr = ref_ptr->next ) { /* nothing happens here */; }
00550         ref_ptr->next = new_ref;
00551 
00552         if ( debug.memory == YES )
00553         {
00554                 printf ( "debug: memory: allocated new_buf %p\n", new_buf );
00555                 printf ( "debug: memory: allocated new_ref %p\n", (void *) new_ref );
00556         }
00557 
00558         return new_buf;
00559 }
00560 
00561 /*
00562  * drop any and all unneeded root privs -- called ASAP after start
00563  * patch from jdassen
00564  */
00565 void dropexcesscapabilities( void )
00566 {
00567 #ifdef HAVE_LIBCAP
00568         cap_t cap_d = cap_init();
00569         cap_value_t cap_values[] = {
00570                 /* capabilities we need to keep */
00571                 CAP_NET_RAW
00572         };
00573 
00574         if (!cap_d) {
00575                 fprintf(stderr, "Could not alloc cap struct\n");
00576                 exit(-1);
00577         }
00578 
00579         cap_clear(cap_d);
00580         cap_set_flag(cap_d, CAP_PERMITTED, 1, cap_values, CAP_SET);
00581         cap_set_flag(cap_d, CAP_EFFECTIVE, 1, cap_values, CAP_SET);
00582 
00583         if (cap_set_proc(cap_d) != 0) {
00584                 fprintf(stderr, "Could not set capabilities: %s\n", strerror(errno));
00585                 exit(1);
00586         }
00587         cap_free(&cap_d);
00588 #endif /* HAVE_LIBCAP */
00589 }
00590 
00591 
00592 /*************************
00593  * Debugging starts here *
00594  *************************/
00595 
00596 void parse_debug ( char * optarg )
00597 {
00598         size_t i;
00599 
00600         for ( i = 0; i < strlen ( optarg ); i++ )
00601         {
00602                 switch ( optarg [ i ] )
00603                 {
00604                 case 'a':
00605                         printf ( "debug: all\n" );
00606                         debug.loop = YES;
00607                         debug.interface = YES;
00608                         debug.send_buf = YES;
00609                         debug.recv_buf = YES;
00610                         debug.packet_length = YES;
00611                         debug.memory = YES;
00612                         break;
00613                 case 'i':
00614                         printf ( "debug: interface\n" );
00615                         debug.interface = YES;
00616                         break;
00617                 case 'l':
00618                         printf ( "debug: packet_length\n" );
00619                         debug.packet_length = YES;
00620                         break;
00621                 case 'r':
00622                         printf ( "debug: recv_buf\n" );
00623                         debug.recv_buf = YES;
00624                         break;
00625                 case 's':
00626                         printf ( "debug: send_buf\n" );
00627                         debug.send_buf = YES;
00628                         break;
00629                 case 't':
00630                         printf ( "debug: timestamp\n" );
00631                         debug.timestamp = YES;
00632                         break;
00633                 case 'A':
00634                         printf ( "debug: as_lookup\n" );
00635                         debug.as_lookup = YES;
00636                         break;
00637                 case 'm':
00638                         printf ( "debug: memory\n" );
00639                         debug.memory = YES;
00640                         break;
00641                 default:
00642                         printf ( "debug: invalid debug flag: %c\n", optarg [ i ] );
00643                         break;
00644                 }
00645         }
00646         
00647 }
00648 
00649 /*
00650  * Debugging function
00651  */
00652 void debug_packet ( const u_int8_t * const raw, const u_int bytes )
00653 {
00654         u_int i;
00655 
00656         /* set i to 1 rather than 0 so that the mod for spaces
00657          * and \n's are easier */
00658         for ( i = 1; i <= bytes; i++ )
00659         {
00660                 printf ( "%02x", raw [ i - 1 ] );
00661                 if ( ( i % 2  ) == 0 ) { printf ( " "  ); }
00662                 if ( ( i % 16 ) == 0 ) { printf ( "\n" ); }
00663         }
00664         if ( ( i % 16 ) != 0 ) { printf ( "\n" ); }
00665 
00666         return;
00667 }

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