// $Id: prpath.cc,v 4.10 2002/05/16 13:41:05 katie Exp $ // Copyright (c) 2001,2002 RIPE NCC // // All Rights Reserved // // Permission to use, copy, modify, and distribute this software and its // documentation for any purpose and without fee is hereby granted, // provided that the above copyright notice appear in all copies and that // both that copyright notice and this permission notice appear in // supporting documentation, and that the name of the author not be // used in advertising or publicity pertaining to distribution of the // software without specific, written prior permission. // // THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING // ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL // AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY // DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // // // Copyright (c) 1994 by the University of Southern California // All rights reserved. // // Permission to use, copy, modify, and distribute this software and its // documentation in source and binary forms for lawful non-commercial // purposes and without fee is hereby granted, provided that the above // copyright notice appear in all copies and that both the copyright // notice and this permission notice appear in supporting documentation, // and that any documentation, advertising materials, and other materials // related to such distribution and use acknowledge that the software was // developed by the University of Southern California, Information // Sciences Institute. The name of the USC may not be used to endorse or // promote products derived from this software without specific prior // written permission. // // THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY // REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY // PURPOSE. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR // IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, // TITLE, AND NON-INFRINGEMENT. // // IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY // SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT, TORT, // OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH, THE USE // OR PERFORMANCE OF THIS SOFTWARE. // // Questions concerning this software should be directed to // ratoolset@isi.edu. // // Author(s): Cengiz Alaettinoglu // John Mehringer #include "config.h" #include #include #include #include #include #include extern "C" { #if HAVE_UNISTD_H # include #endif } #include "util/Argv.hh" #include "util/net.hh" #include "util/rusage.hh" #include "util/debug.hh" #include "util/trace.hh" #include "util/version.hh" #include "rpsl/schema.hh" #include "irr/irr.hh" #include "irr/autnum.hh" #include "irr/rawhoisc.hh" #include "irr/ripewhoisc.hh" #include "bgp/bgproute.hh" //IRR * irr; // Global variable defined in irr/irr.cc // Used for bug static ASt source_as; // AS number of source for prpath trace static IRR * whois; // Connection to IRR server for query static ActionDictionary * actiondictionary; Rusage ru; static char * destination_arg; static IPAddr * destination_ip = NULL; static Prefix * destination_prefix = NULL; static ASt destination_as; int opt_rusage = 0; char *opt_prompt = "prpath> "; char *opt_my_as = NULL; int opt_echo_as = 0; int opt_max_path_length = 8; int path_length_limit = 12; int opt_interactive = 1; extern int BGPROUTE_MAX_ASPATH_LENGTH; void Announce(BGPRoute &bgproute, ASt as); //-------------------------------------------------------------- // void usage(char *argv[]) // // //-------------------------------------------------------------- void usage(char *argv[]) { cerr << "Usage: " << argv[0] << " to be written later" << endl; exit(1); } //-------------------------------------------------------------- // int start_tracing(char *dst, char *key, char *nextArg) // // //-------------------------------------------------------------- int start_tracing(char *dst, char *key, char *nextArg) { if (nextArg) { trace.enable(nextArg); return 1; // return 1 to signify nextArg is used by us } return 0; } //-------------------------------------------------------------- // int start_debugging(char *dst, char *key, char *nextArg) // // //-------------------------------------------------------------- int start_debugging(char *dst, char *key, char *nextArg) { if (nextArg) { Debug(dbg.enable(atoi(nextArg))); return 1; // return 1 to signify nextArg is used by us } return 0; } //-------------------------------------------------------------- // void init_and_set_options (int argc, char **argv, char **envp) // // //-------------------------------------------------------------- void init_and_set_options (int argc, char **argv, char **envp) { ArgvInfo argTable[] = { // RAToolSet common arguments // key, type, src, dst, help {"-T", ARGV_FUNC, (char *) &start_tracing, (char *) NULL, "Start tracing the next argument"}, {"-D", ARGV_FUNC, (char *) &start_debugging, (char *) NULL, "Start debugging the next argument"}, {"-version", ARGV_FUNC, (char *) &version, (char *) NULL, "Show version"}, {"-rusage", ARGV_BOOL, (char *) NULL, (char *) &opt_rusage, "On termination print resource usage"}, {"-prompt", ARGV_STRING, (char *) NULL, (char *) &opt_prompt, "Prompt"}, IRR_COMMAND_LINE_OPTIONS, // prpath specific arguments {"-as", ARGV_STRING, (char *) NULL, (char *) &opt_my_as, "AS number of the aut-num object to use."}, {"-mpl", ARGV_INT, (char *) NULL, (char *) &opt_max_path_length, "Max path length"}, {(char *) NULL, ARGV_END, (char *) NULL, (char *) NULL, (char *) NULL} }; IRR::handleEnvironmentVariables(envp); IRR::IgnoreErrors(NULL, NULL, NULL); if (ParseArgv(&argc, argv, argTable, 0) != ARGV_OK) { cerr << endl; exit(1); } // Setup Connection to IRR server if (! (whois = IRR::newClient())) { cerr << "Unknown protocol!" << endl; exit(1); } if (opt_max_path_length) BGPROUTE_MAX_ASPATH_LENGTH = opt_max_path_length; // if there are remaining arguments // the first one is my as number // the second one is a destination prefix switch (argc) { case 3 : opt_my_as = argv[1]; case 2: destination_arg = argv[argc - 1]; if ((destination_arg[0] == 'A' || destination_arg[0] == 'a') && (destination_arg[1] == 'S' || destination_arg[1] == 's')) { destination_as = atoi(destination_arg + 2); } else if (strchr(destination_arg,'/')) { destination_prefix = new Prefix(destination_arg); } else { destination_ip = new IPAddr(destination_arg); destination_prefix = new Prefix(destination_ip->Prefix::get_text()); } opt_interactive = 0; case 1: break; default: cerr << "Wrong number of arguments..." << endl; exit(-1); } if (opt_my_as) source_as = atoi(opt_my_as + 2); else { ipAddr myip; myip.setToMyHost(); if ((source_as = whois->getOrigin("%s/32", myip.getIpaddr())) == 0) { cerr << "prpath could not guess your AS number, " "please specify an AS number on the command line." << endl; delete whois; exit(1); } } // have a prompt only if the input is coming from a tty if (!opt_interactive || !isatty(fileno(stdin)) || !isatty(fileno(stdout))) opt_prompt = NULL; } //------------------------------------------------------------- // void Import(BGPRoute &bgproute, ASt export_as, ASt import_as, // IPAddr *import_ip, IPAddr *export_ip) // // export_as was the current as import_as is the peer_as // from IterateExports and // // Now we have to check to see if the peer as will import the // current as since BGP works from destination to source // // import_ip & export_ip are the ip addresses of the routers // // also look at CIDRAdvisor/proxyagg.cc for similar code //------------------------------------------------------------- void Import(BGPRoute &bgproute, ASt export_as, ASt import_as, const IPAddr *import_ip, const IPAddr *export_ip) { const AutNum * import_autnum = NULL; // Check to see if loop is created by adding this AS if (! bgproute.loopCheck(import_as)) { // Get Imports from IRR import_autnum = whois->getAutNum(import_as); if (import_autnum) { AutNumSelector import_itr(import_autnum, "import", NULL, export_as, export_ip, import_ip); if (const FilterAction * fa = import_itr.first()) { for (; fa; fa = import_itr.next()) { // if not at max nodes in route // then continue depth first search if (!bgproute.atMaxRouteLength()) { if (bgproute.isMatching(import_as, fa->filter, whois)) { if (import_as == bgproute.source) { // Have we found the source // If we have found the source as then print out our route bgproute.print(); } else { bgproute.executeAction(fa->action, actiondictionary); Announce(bgproute, import_as); } } // end if (bgproute.isMatching()) } else { //cerr << " Max Path length reached." << endl; } } // end for } else { //No Imports then Check defaults // cerr << " No Imports! Checking for default..." << endl; AttrIterator itr(import_autnum, "default"); for (const AttrDefault * ad = itr.first(); ad; ad = itr.next()) { if (! bgproute.atMaxRouteLength()) { if (bgproute.isMatching(import_as,ad->filter, whois)) { if (import_as == bgproute.source) { // Check to see if we found the source bgproute.print(); } else { bgproute.executeAction(ad->action, actiondictionary); Announce(bgproute, import_as); } } // end if (bgproute.isMatching } else { //cerr << "Max Path length reached." << endl; } } // end for } } // end if (import_autnum) } // end if (! bgproute.loopCheck()) } //-------------------------------------------------------------- // void IterateExports(BGPRoute &bgproute, ASt as, AutNum * as_autnum, // ASt peer_as, IPAddr * peer_ip, IPAddr * local_ip) // // Find export filter which contain peer_as, // Loop over list of exports, // Execute the actions for that export filter // // peer_ip & local_ip are ip addresses for the routers //------------------------------------------------------------- void IterateExports(BGPRoute &bgproute, ASt as, const AutNum * as_autnum, ASt peer_as, const IPAddr * peer_ip, const IPAddr * local_ip) { // Get matching Export Filter-Actions AutNumSelector export_itr(as_autnum, "export", NULL, peer_as, peer_ip, local_ip); const FilterAction * fa; BGPRoute * import_route; // Check each Export filter for possible correct route for (fa = export_itr.first(); fa; fa = export_itr.next()) { import_route = new BGPRoute(bgproute); // Duplicate the currrent BGPRoute // to check this possible path // For each export check if they allow the current AS's // traffic on their network by looking at the peer AS's imports // Import(bgproute, current as, ip of current as, peer AS, peer IP address) import_route->executeAction(fa->action, actiondictionary); Import(*import_route, as, peer_as, peer_ip, local_ip); delete import_route; // We are done with it } } //-------------------------------------------------------------- // void Announce(BGPRoute &r, ASt as) // Analogous to a bgp AS announcement // Check exports of current AS to see where to go next // doing a recursive depth first search on each export // it terminates when either the max route length is reached // or the BGP's source AS is found // // Announce()-->IterateExports()-->Imports()-->Announce()...until path is found //------------------------------------------------------------- void Announce(BGPRoute &bgproute, ASt as) { const AutNum * as_autnum = whois->getAutNum(as); ASt peer_as; bgproute.add(as); // Add the current AS as to the BGPRoute path list if (as_autnum) { // Do we have an autnum record for this as? // Find all peers of current AS AutNumPeeringIterator itr(as_autnum); for (const Peering *peering = itr.first(); itr; peering = itr.next()){ // Get exports containing peerAS and check the imports of the peer IterateExports(bgproute, as, as_autnum, peering->peerAS, &peering->peerIP, &peering->localIP); } // End for } else cerr << "Warning: No autnum record found for AS" << as << endl; } //------------------------------------------------------------- // main (int argc, char **argv, char **envp) // // //------------------------------------------------------------- main (int argc, char **argv, char **envp) { const AutNum * myAutNum; BGPRoute * bgproute; schema.initialize(); init_and_set_options(argc, argv, envp); irr = whois; // For irr/autnum.hh AutNumIterator::isMatching(Attribute *attr) actiondictionary = new ActionDictionary; if (destination_prefix != NULL) { bgproute = new BGPRoute(source_as, destination_prefix, whois); } else { bgproute = new BGPRoute(source_as, destination_as); } /* myAutNum = irr->getAutNum(2764); AutNumPeeringIterator itr(myAutNum); for (const Peering *peering = itr.first(); itr; peering = itr.next()) { cout << "AS" << peering->peerAS; if (!peering->peerIP.isNull()) cout << " " << peering->peerIP; if (!peering->localIP.isNull()) cout << " at " << peering->localIP; cout << "\n"; } exit(1);*/ // by katie@ripe.net - if route is non-existent if (bgproute->origin->list.head() == NULL) cout << "Unable to lookup destination AS" << endl; // Start the search from destination to the source AS for (ItemASNO * asln = bgproute->origin->list.head(); asln; asln = bgproute->origin->list.next(asln)) { if (asln->asno) { cout << "Route:" << endl; cout << " NLRI: "; if (destination_prefix) cout << destination_arg << endl; else cout << "don't care" << endl; cout << " Origins: AS" << asln->asno << endl; Announce(*bgproute, asln->asno); } else cout << "Unable to lookup destination AS" << endl; } delete irr; delete actiondictionary; }