//========================================================================== // // Copyright 2001 The Regents of the University of California // All Rights Reserved // // Permission to use, copy, modify and distribute any part of this skitterTrace // for educational, research and non-profit purposes, without fee, and without // a written agreement is hereby granted, provided that the above copyright // notice, this paragraph and the following paragraphs appear in all copies. // // Those desiring to incorporate this into commercial products or use for // commercial purposes should contact the // // Technology Transfer Office, University of California, San Diego, // 9500 Gilman Drive, La Jolla, CA 92093-0910 // Ph: (619) 534-5815, FAX: (619) 534-7345. // // IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR // DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING // LOST PROFITS, ARISING OUT OF THE USE OF THIS SK_ANALYSIS_DUMP, EVEN IF THE // UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // THE SK_ANALYSIS_DUMP, PROVIDED HEREIN IS ON AN "AS IS" BASIS, AND THE // UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, // UPDATES, ENHANCEMENTS, OR MODIFICATIONS. THE UNIVERSITY OF CALIFORNIA MAKES // NO REPRESENTATIONS AND EXTENDS NO WARRANTIES OF ANY KIND, EITHER IMPLIED OR // EXPRESS, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE // SK_ANALYSIS_DUMP WILL NOT INFRINGE ANY PATENT, TRADEMARK OR OTHER RIGHTS. // // sk_analysis_dump is developed by Bradley L. Huffaker at the University of // California, San Diego under the Cooperative Association for // Internet Data Analysis (CAIDA) Program. Support for this effort is // provided by DARPA grant N66001-98-2-8922 and by CAIDA members. //========================================================================== // // This program prints out a perl friendly version of ArtsIpPathData. // In order to do this is does some simple preanalysis. // #include #include #include #include #include #include #include "Arts.hh" #include "caida_t.h" #include "config.h" #include "PrintHeaderComments.h" #ifdef USE_ZFSTREAM_ #include "zfstream.h" #endif #ifdef USE_NETACUITY_ #include "netacuity_api.h" #endif #define NETACUITY_SERVER_STRING "NETACUITY_SERVER" #define MAX_NUM_HOPS 300 #define MAX_NUM_IPS 100 #define MAX_NUM_HOPS_PRINT_ERROR 255 #define MAX_NUM_IPS_PRINT_ERROR 3 #define MAX_NUM_SKIPPED_HOPS 5 #define FORMAT_DEFAULT 0 #define FORMAT_SIMPLE 1 #define FORMAT_DATABASE 2 #define IP_STRING_LENGTH 17 using namespace std; //------------------------------------------------------------------------- // void Usage(const char *argv0) //......................................................................... // //------------------------------------------------------------------------- void Usage(const char *argv0) { cerr << "Usage: " << argv0 << " [-sdtrHpiheo"; #ifdef USE_NETACUITY_ cerr << "g] [-G server"; #endif cerr << "] [-S skip_lines] [-D stop_lines] file(s)" << endl; return; } //------------------------------------------------------------------------- // void PrintHelp() //......................................................................... // //------------------------------------------------------------------------- void PrintHelp() { cerr << " This program prints out skitter Arts traces.\n"; cerr << " C - hide comments\n"; cerr << " o - old format version 1.0\n"; cerr << " s - hide Source \n"; cerr << " d - hide Destination \n"; cerr << " l - hide list number\n"; cerr << " c - hide cycle number\n"; cerr << " t - hide Timestamp \n"; cerr << " r - hide Reply Fields\n"; cerr << " DestReplied, DestRTT, RequestTTL, ReplyTTL \n"; cerr << " H - hide Halt Fields \n"; cerr << " HaltReason, HaltReasonData\n"; cerr << " p - hide Path Fields \n"; cerr << " PathComplete, PerHopData\n"; cerr << " i - hides hop non IP data\n"; cerr << " HopRTT, HopNumTries\n"; cerr << endl; cerr << " e - add Destination to Ending\n"; cerr << endl; cerr << " D numline - debug mode that only reads the first numline\n"; cerr << " of arts objects\n"; cerr << " S numline - skips first numline of art objects in the file\n"; cerr << endl; #ifdef USE_NETACUITY_ cerr << " g - print out geographical information\n"; cerr << " assuming that environmental variable " << NETACUITY_SERVER_STRING << " is set\n"; cerr << " to the NETACUITY server\n"; cerr << " G servername - the same as g except it uses the servername\n"; cerr << " given on the command line.\n"; cerr << endl; #endif cerr << " h - prints this message\n"; cerr << endl; return; } //------------------------------------------------------------------------- // Stream Control Functions //------------------------------------------------------------------------- // // PrintStream // Reads through the istream and passes arts objects it finds // to ProcessArts. It also handles skipping lines at the front // and prematurly ends reading. // ProcessArts // Processes the individual Arts object and called the required // Print functions on it's individual parts. //------------------------------------------------------------------------- void ProcessStream(const char * argv0, const char * stream_name, control_struct * control, istream * stream); void ProcessArts(const char * stream_name, control_struct * control, Arts * arts); //------------------------------------------------------------------------- // Output functions //------------------------------------------------------------------------- // The following print out the fields depending on flags set in // control. //......................................................................... // PrintHeaderFields // Destination, Source, and Timestamp // PrintReplyFields // Destination Replied, Destination RTT, Request TTL and Reply TTL // PrintHaltFields // HaltReason, halt_reason_data // PrintPathFields // PathComplete, per hop IP,RTT,numTries //------------------------------------------------------------------------- void PrintHeaderFields (control_struct * control, vector::const_iterator creationAttribute, ArtsIpPathData * ipPathData); void PrintReplyFields (control_struct * control, ArtsIpPathData * ipPathData); void PrintHaltFields (control_struct * control, ArtsIpPathData * ipPathData); void PrintOldFields (control_struct * control, vector::const_iterator creationAttribute, ArtsIpPathData * ipPathData); void PrintPathFields (const char * stream_name, control_struct * control, vector::const_iterator creationAttribute, ArtsIpPathData * ipPathData); //------------------------------------------------------------------------- // Geographic Functions //------------------------------------------------------------------------- // // SetupNetacuityServer // Open connection to Netacuity server or fail and die. // PrintGeoInfo // Print out the Geographic information for a single IP address. // PrintPathGeoInfo // Walk a IpPathData object and call PrintGeoInfo on each IP in // the path. //------------------------------------------------------------------------- void SetupNetacuityServer(char * server); void PrintGeoInfo(FILE * output, control_struct * control, ipv4addr_t ip); void PrintPathGeoInfo (FILE * output, control_struct * control, ArtsIpPathData * ipPathData); //------------------------------------------------------------------------- // int main(int argc, char *argv[]) //......................................................................... // //------------------------------------------------------------------------- int main(int argc, char *argv[]) { int opt; #ifdef USE_NETACUITY_ char * na_server = getenv(NETACUITY_SERVER_STRING); #endif control_struct control; while ((opt = getopt(argc, argv, "oeCsdlctrHpiS:D:gG:h")) >= 0) { if (opt == 'S') { control.skip_numlines = atoi(optarg); } else if (opt == 'D') { control.debug_mode = true; control.debug_numlines = atoi(optarg); } else if (opt == 'e') { control.addDestEnd = true; } else if (opt == 'o') { control.oldFormat = true; } else if (opt == 'C') { control.hideComments = true; } else if (opt == 's') { control.hideSource = true; } else if (opt == 'd') { control.hideDestination = true; } else if (opt == 'l') { control.hideListId = true; } else if (opt == 'c') { control.hideCycleId = true; } else if (opt == 't') { control.hideTimestamp = true; } else if (opt == 'r') { control.hideReply = true; } else if (opt == 'H') { control.hideHalt = true; } else if (opt == 'p') { control.hidePath = true; } else if (opt == 'i') { control.hideIntermediate = true; #ifdef USE_NETACUITY_ } else if (opt == 'g') { control.print_geo_info = true; } else if (opt == 'G') { control.print_geo_info = true; na_server = new char[strlen(optarg)+1]; strcpy(na_server, optarg); #endif } else if (opt == 'h') { Usage(argv[0]); PrintHelp(); exit(0); } else { Usage(argv[0]); exit(-1); } } #ifdef USE_NETACUITY_ if (true == control.print_geo_info) { if (NULL == na_server) { Usage(argv[0]); cerr << " ERROR::" << NETACUITY_SERVER_STRING << " is empty please use -G netacuity_server\n"; exit(0); } SetupNetacuityServer(na_server); } #endif if (false == control.hideComments) PrintHeaderComments(&control); if (optind < argc) { for (int fileNum = optind; fileNum < argc; fileNum++) { #ifdef USE_ZFSTREAM_ istream * artsStream = new gzifstream(argv[fileNum]); #else ifstream * artsStream = new ifstream(argv[fileNum]); #endif if (! artsStream || ! *artsStream) { cerr << "unable to open " << argv[fileNum] << endl; if (false == control.hideComments) cout << "# unable to open " << argv[fileNum] << endl; } else { ProcessStream(argv[0], argv[fileNum], &control, artsStream); // delete the input stream. delete(artsStream); } } } else { ProcessStream(argv[0], "STDIN", &control, &cin); } } void ProcessStream(const char * argv0, const char * stream_name, control_struct * control, istream * stream) { Arts *arts; int num_found = 0; while (*stream && (!control->debug_mode || num_found < control->debug_numlines )){ arts = new Arts(); // read an Arts object. arts->read(*stream); if (! *stream) { // error or EOF while reading delete(arts); break; } num_found++; if (num_found > control->skip_numlines) ProcessArts(stream_name, control, arts); // delete the object. delete(arts); } if (false == control->hideComments) printf("#END %s DATA %s\n", argv0, stream_name); } void ProcessArts(const char * stream_name, control_struct * control, Arts * arts) { // Skip objects that aren't IP path objects. if (arts->Header().Identifier() != artsC_OBJECT_IP_PATH) { return; } // Get a pointer to the path data stored in the Arts object. ArtsIpPathData * ipPathData = arts->IpPathData(); // Do whatever you want with ipPathData using members of the // ArtsIpPathData class. For example, print the RTT if the // destination was reached. // The following checks will provide you with only complete // paths where the destination and all the intermediate hops // were also reached. // IsComplete is not well named. It only means that the // destination was reached. vector::const_iterator creationAttribute = arts->FindCreationAttribute(); //bool hideInitermidateRtt = false; if (creationAttribute != arts->Attributes().end()) { if (control->print_geo_info ) { if (false == control->hideSource) PrintGeoInfo(stdout, control, ipPathData->Src()); if (false == control->hideDestination) PrintGeoInfo(stdout, control, ipPathData->Dst()); if (false == control->hidePath) PrintPathGeoInfo(stdout, control, ipPathData); } // This flags the line as a trace object. if (false == control->oldFormat) { printf ("T"); PrintHeaderFields(control, creationAttribute, ipPathData); if (false == control->hideReply) PrintReplyFields(control, ipPathData); if (false == control->hideHalt) PrintHaltFields(control, ipPathData); } if (false == control->hidePath || true == control->oldFormat) PrintPathFields(stream_name, control, creationAttribute, ipPathData); printf ("\n"); } } void PrintHeaderFields(control_struct * control, vector::const_iterator creationAttribute, ArtsIpPathData * ipPathData){ // Print out the Trace Header information in_addr addr; if (false == control->hideSource) { addr.s_addr = ipPathData->Src(); printf ("\t%s", inet_ntoa(addr)); } if (false == control->hideDestination) { addr.s_addr = ipPathData->Dst(); printf ("\t%s", inet_ntoa(addr)); } if (false == control->hideListId) { uint32_t listId = ipPathData->ListId(); printf ("\t%u", listId); } if (false == control->hideCycleId) { uint32_t cycleId = ipPathData->CycleId(); printf ("\t%u", cycleId); } if (false == control->hideTimestamp) { const long int sample_time = (*creationAttribute).Creation(); printf ("\t%lu", sample_time); } } void PrintReplyFields(control_struct * control, ArtsIpPathData * ipPathData) { if (ipPathData->IsComplete()) { double total_rtt = (ipPathData->Rtt().tv_sec * 1000.0) + (ipPathData->Rtt().tv_usec / 1000.0); printf ("\tR\t%.3f\t%d\t%d", total_rtt, ipPathData->HopDistance(), ipPathData->ReplyTtl()); } else { printf ("\tN\t0\t0\t0"); } } void PrintHaltFields (control_struct * control, ArtsIpPathData * ipPathData) { switch (ipPathData->HaltReason()) { case ArtsIpPathData::k_noHalt : printf ("\tS\t0"); break; case ArtsIpPathData::k_icmpUnreachable : printf ("\tU\t%d", ipPathData->IcmpCode()); break; case ArtsIpPathData::k_loopDetected : printf ("\tL\t%d", ipPathData->LoopLength()); break; case ArtsIpPathData::k_gapLimitExceeded : printf ("\tG\t%d", ipPathData->GapLimit()); break; default : printf ("\t?\t0"); } } void PrintPathFields (const char * stream_name, control_struct * control, vector::const_iterator creationAttribute, ArtsIpPathData * ipPathData) { vector & pathHops = ipPathData->Path(); vector::const_iterator hopIter; int last_hop_seen = 0; ipv4addr_t ip_per_hop[MAX_NUM_HOPS][MAX_NUM_IPS]; uint8_t numTries_per_hop[MAX_NUM_HOPS][MAX_NUM_IPS]; double rtt_per_hop[MAX_NUM_HOPS][MAX_NUM_IPS]; int num_ips[MAX_NUM_HOPS]; for (int i=0; i < MAX_NUM_HOPS; i++) { num_ips[i] = 0; } // This loops has two purposes: // it sorts the hops which is not guaranteed by skitter // it also organized IP by hops so they can be printed // together for (hopIter = pathHops.begin(); hopIter != pathHops.end(); hopIter++) { in_addr addr; addr.s_addr = ipPathData->Dst(); int hop = (*hopIter).HopNum(); if (hop >= MAX_NUM_HOPS) { fprintf (stderr, "Found in `%s' for destination `%s' more than %d hops\n", stream_name, inet_ntoa(addr), MAX_NUM_HOPS); return; } if (num_ips[hop] >= MAX_NUM_IPS) { fprintf (stderr, "Found in `%s' for destination `%s' more than %d ips\n", stream_name, inet_ntoa(addr), MAX_NUM_IPS); return; } ipv4addr_t ip = (*hopIter).IpAddr(); ip_per_hop[hop][num_ips[hop]] = ip; if (control->print_geo_info ) { PrintGeoInfo(stdout, control, ip); } double rtt = ((*hopIter).Rtt().tv_sec * 1000.0) + ((*hopIter).Rtt().tv_usec/ 1000.0); numTries_per_hop[hop][num_ips[hop]] = (*hopIter).NumTries(); rtt_per_hop[hop][num_ips[hop]] = rtt; num_ips[hop]++; if (last_hop_seen < hop) last_hop_seen = hop; } char pathComplete = 'I'; if (ipPathData->IsComplete()) { int dst_hop = ipPathData->HopDistance(); int hop = 1; while (num_ips[hop] > 0 && hop < dst_hop) { hop++; } if (hop == dst_hop) { pathComplete = 'C'; } else if (true == control->oldFormat) { pathComplete = 'I'; } if (true == control->addDestEnd) { ip_per_hop[dst_hop][num_ips[dst_hop]] = ipPathData->Dst(); rtt_per_hop[dst_hop][num_ips[dst_hop]] = (ipPathData->Rtt().tv_sec * 1000.0) + (ipPathData->Rtt().tv_usec / 1000.0); num_ips[dst_hop]++; last_hop_seen = dst_hop; } } else if (true == control->oldFormat) { pathComplete = 'N'; } if (false == control->oldFormat) printf("\t%c",pathComplete); else printf("%c",pathComplete); if (true == control->oldFormat) PrintOldFields(control, creationAttribute, ipPathData); if (true == control->addDestEnd) { in_addr addr; addr.s_addr = ipPathData->Src(); printf("\t%s",inet_ntoa(addr)); if (false == control->hideIntermediate) printf(",0.000,0"); } for (int hop=1; hop <= last_hop_seen; hop++) { // If the simple_format is set is false and more than one IP were // found for a given hop, that hop must be left undecided int ip_index = 0; if (false == control->oldFormat) { printf ("\t"); } else { printf (" "); } if (num_ips[hop] > 0) { while (ip_index < num_ips[hop]) { in_addr addr; addr.s_addr = ip_per_hop[hop][ip_index] ; uint8_t numTries = numTries_per_hop[hop][ip_index]; double rtt = rtt_per_hop[hop][ip_index]; if (false == control->hideIntermediate && false == control->oldFormat) { printf ("%s,%.3f,%d", inet_ntoa( addr), rtt, numTries); } else { printf ("%s", inet_ntoa( addr)); } ip_index++; if (ip_index < num_ips[hop]) { if (false == control->oldFormat) printf (";"); else printf (","); } } } else { printf ("q"); } } } void PrintOldFields (control_struct * control, vector::const_iterator creationAttribute, ArtsIpPathData * ipPathData) { in_addr src_addr; in_addr dst_addr; src_addr.s_addr = ipPathData->Src(); dst_addr.s_addr = ipPathData->Dst(); const long int sample_time = (*creationAttribute).Creation(); int num_hops = ipPathData->HopDistance(); double rtt = (ipPathData->Rtt().tv_sec * 1000.0) + (ipPathData->Rtt().tv_usec / 1000.0); printf(" %s",inet_ntoa(src_addr)); printf(" %s %lu %.3f %d",inet_ntoa(dst_addr), sample_time, rtt, num_hops); } //----------------------------------------------------------- // Below is the Netaquity code. //----------------------------------------------------------- void SetupNetacuityServer(char * server) { #ifdef USE_NETACUITY_ int not_ip; char ip_buffer[17]; char * server_ip; struct in_addr scratch; struct addrinfo hints, *ai_list; not_ip = !inet_pton(AF_INET, server, &scratch); if (not_ip) { memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; /* to support IPv6, just delete this line */ if (getaddrinfo(server, NULL, &hints, &ai_list) == 0) { inet_ntop(ai_list->ai_family, &(((struct sockaddr_in*)(ai_list->ai_addr))->sin_addr), ip_buffer, 17); server_ip = ip_buffer; freeaddrinfo(ai_list); } else { fprintf(stderr,"Failed to resolve hostname \"%s\"\n",server); exit(-1); } } else { server_ip = server; } if ( !(na_api_set_server_addr(server_ip)) ) { fprintf(stderr,"Error in setting server addr.\n"); exit(-1); } #endif } void PrintPathGeoInfo (FILE * out, control_struct * control, ArtsIpPathData * ipPathData) { vector & pathHops = ipPathData->Path(); vector::const_iterator hopIter; for (hopIter = pathHops.begin(); hopIter != pathHops.end(); hopIter++) { ipv4addr_t ip = (*hopIter).IpAddr(); PrintGeoInfo(out, control, ip); } } void PrintGeoInfo(FILE * output, control_struct * control, ipv4addr_t ip) { #ifdef USE_NETACUITY_ if (control->seen_ip.find(ip) != control->seen_ip.end()) return; control->seen_ip.insert(ip); na_geo_struct answer; in_addr addr; addr.s_addr = ip; if (!na_query_geo(inet_ntoa(addr), &answer) ) { fprintf(stderr,"Error in nq_query_geo(%s)\n",inet_ntoa(addr)); } else { fprintf( output, "G\t%s\t",inet_ntoa(addr)); fprintf( output, "%s=%d\t", answer.country, answer.country_c); fprintf( output, "%s=%d\t", answer.region, answer.region_c); fprintf( output, "%s=%d\t", answer.city, answer.city_c); fprintf( output, "%s\t", answer.speed); fprintf( output, "%d\t", answer.metro_code); fprintf( output, "%.3f\t", answer.latitude); fprintf( output, "%.3f", answer.longitude); fprintf(output, "\n"); } #endif }