Router/004075500010200000062000000000000712617622200135625ustar00cjosephsysengr00000400000366Router/LG/004075500010200000062000000000000712644617500140735ustar00cjosephsysengr00000400000366Router/LG/LG.pm010064400010200000062000000234220713140475200147220ustar00cjosephsysengr00000400000366#!/usr/local/bin/perl # LG (Looking Glass) # by Chris Josephes # # A framework for accessing information on routers # remotely # # Package Definition # package Router::LG; # # Includes # # # Global Variables # # Software version $VERSION=0.98; # Table of Submodules of LG %Loaded=(); # Default TTL for cached data $DefaultTTL=600; # # Constructor Method # # # new # Construct a new LG object sub new { my ($object)={}; bless ($object); return($object); } # # version # Return version data of the LG class sub version { return($VERSION); } # # Data Methods # # # router # Set/Get the router stucture that we will be accessing sub router { my ($self,$router)=@_; if ($router) { $self->{"router"}=$router; $self->_loadDriver($router->{"-class"}); unless ($self->{"router"}->{"-driver"}) { return(undef); } } return($self->{"router"}); } # # parameters # Set/Get the parameters to be parsed into the command string # passing "-remove" clears the array sub parameters { my ($self,@list)=@_; #print("Params Called\n"); if (@list) { if ($list[0] eq "-clear") { $self->{"parameters"}=[]; } else { while (@list) { push(@{$self->{"parameters"}},shift(@list)); } } } return(@{$self->{"parameters"}}); } # # cache # Sets/Gets caching setup # arguements: -directory (cache directory) -ttl (time to live in secs) sub cache { my ($self,%args)=@_; if (%args) { if ($args{"-directory"}) { # determine if directory is safe if (-d $args{"-directory"}) { $self->{"cache"}->{"-directory"}=$args{"-directory"}; } else { $self->error("Cache directory does not exist."); } } $self->{"cache"}->{"-ttl"}=$args{"-ttl"} || $DefaultTTL; } return(%{$self->{"cache"}}); } # # commands # Returns a list of commands the router driver understands sub commands { my ($self)=@_; my ($driver); $driver=$self->_driver(); if ($driver) { return($driver->commands()); } else { $self->error("Driver class not yet defined"); return(undef); } } sub command { my ($self,$command,@rest)=@_; my ($driver); $driver=$self->_driver(); if ($driver) { if (@rest) { $driver->command($command,@rest); } return($driver->command($command)); } else { $self->error("Driver class not yet defined"); return(undef); } } sub cmdlabels { my ($self)=@_; my ($cmd,@list,%lhash,%th); (@list)=$self->commands(); print("LIST: ",@list,"\n"); while (@list) { $cmd=pop(@list); (%th)=$self->command($cmd); $lhash{$cmd}=$th{"-label"}; } return(%lhash); } # # Cache Control Methods # # # _cacheOK # Determine if cached data from a command is valid by checking the following: # - If parameters were passed with the command # - If the command can be cached # - If the previously cached data is still valid sub _cacheOK { my ($self,$command)=@_; my ($file,$update,$age); return (undef) if ($self->parameters()); $file=$self->_cacheFile($command); if (-e $file) { (undef,undef,undef,undef,undef,undef,undef,undef,undef,$update)= stat($file); $age=time()-$update; return($age < $self->{"cache"}->{"-ttl"} ? 1 : 0); } else { return(undef); } } # # _readCache # Read cached output from an earlier execution sub _readCache { my ($self,$command)=@_; my ($file,$x); $file=$self->_cacheFile($command); open (F, $file) || return(undef); while ($x=) { push(@output,$x); } close(F); return(@output); } # # _writeCache # Copy data from a router to a cachefile sub _writeCache { my ($self,$command,@output)=@_; my ($file); $file=$self->_cacheFile($command); open (F, ">$file") || return(undef); print F (@output); close(F); } # # Execution Methods # # # parse # Return the command string the driver would send to the router sub parse { my ($self,$command)=@_; my ($driver,$string); $driver=$self->_driver(); $string=$driver->parse($command); return($string); } # # execute # Have the driver send the command and parameters to the router sub execute { my ($self,$command)=@_; my ($driver,$cs,@output); $driver=$self->_driver(); #print("REF2:",ref($driver),"\n"); #print("Determining cache\n"); if ($driver->cachable($command)) { if ($self->_cacheOK($command)) { #print("Cached data\n"); (@output)=$self->_readCache($command); $cs=1; } else { #print("Active data\n"); # (@output)=&{$class."::exec"}($self,$command); (@output)=$driver->exec($command); $cs=0; # Now send this data to the cache! $self->_writeCache($command,@output); } } else { #print("Active data\n"); #(@output)=&{$class."::exec"}($self,$command); (@output)=$driver->exec($command); $cs=0; } return($cs,@output); } # # error # Set or return an error message sub error { my ($self,@msgs)=@_; if (@msgs) { if ($msgs[0] eq "-clear") { $self->{ec}=[]; } else { while (@msgs) { my ($err,$pkg); $err=shift(@msgs); $pkg=caller(); $err="$pkg => $err\n"; # print("E: $err"); push(@{$self->{ec}},$err); } } } if ($self->{ec}) { return(@{$self->{ec}}) } else { return("LG => No Errors\n"); } } # # Hidden Methods # # # _loadDriver # Load a LG::* class to access a specific router sub _loadDriver { my ($self,$driver)=@_; my ($class); $driver=lc($driver); $driver=ucfirst($driver); $class="Router::LG::".$driver; #print("Attempting to load $class\n"); unless ($Loaded{$driver}) { if (eval "require ($class)") { $Loaded{$driver}=1; } else { $self->error("Loading of ($class) failed"); return(undef); } } $self->{"router"}->{"-driver"}=&{$class."::new"}($self); return($self->{"router"}->{"-driver"}); } # # _driver # Return the driver object sub _driver { my ($self)=@_; return($self->{"router"}->{"-driver"}); } # # _cacheFile # Return a generated cache filename sub _cacheFile { my ($self,$command)=@_; my ($file); $file=$self->{"cache"}->{"-directory"}."/".$command."--". $self->{"router"}->{"-hostname"}; return($file); } # # Exit Block # 1; __END__ # # POD Block # =head1 NAME Router::LG - Looking Glass =head1 SYNOPSIS use Router::LG; $glass=Router::LG::new(); =head1 DESCRIPTION The LG class is based on the lg.pl program originally written by Ed Kern of Digex. The original lg.pl program was used as a web-based front end to obtain information from routers via RSH. All of the original features of lg.pl have been incorporated into LG.pm. - Multiple router vendor support - Multiple parameter support - Custom command definition =head1 HOW IT WORKS The LG module has a set of driver modules for accessing routers made by different vendors, like Cisco or Juniper. Each driver contains code and data structures regarding what commands it can send and how it can communicate with the router. The driver module is dynamically loaded when a router is defined. =head1 CONSTRUCTOR METHOD =over 4 =item $glass=Router::LG->new(); =back =head1 OBJECT METHODS =over 4 =item version(); Returns version data on the Router::LG class. =back =over 4 =item router($ROUTER); Sets or returns the router data structure. The router data structure defines the host address of the router, the vendor class, the remote access method, and any arguements are required to connect. The following code defines a router data structure and tells the Looking Glass object to use it. =over 4 #!/usr/local/bin/perl $router={ -hostname => "core.pop.isp.node", -class => "Cisco", -method => "rsh", -args => { -luser => "local_user", -ruser => "remote_user", }, }; $glass->router($router); =back See the POD documentation for a particular Router::LG class, (ex, Router::LG::Cisco, or Router::LG::Driver) =back =over 4 =item parameters([-clear|@LIST]); Sets or returns an array of parameters that will be inserted into the command sent to the router. Setting the first arguement of the list to "-clear" erases the contents of the array. =back =over 4 =item cache( -directory => $CACHE, -ttl => $TTL); Sets of returns a hash defining the optional cache setup. Defining a cache takes two parameters, a directory, and a default time to live (in seconds). If no TTL is defined, a default value of 10 minutes will be used. =back =over 4 =item commands(); Returns a list of commands the driver supports =back =over 4 =item command($COMMAND,%PARAMETERS); Sets or returns data regarding a command structure. See the POD documentation for the particular vendor class for more information. =back =over 4 =item execute($COMMAND); Executes the command on the router. If the command is successful, the method returns a cache state variable, followed by the lines of output the router sent back. The cache state variable can be a 1 indicating that LG returned cached data instead of accessing the router, or a 0 indicating that the router was accessed to obtain the data. If the command failed, undef will be returned. Example: ($cache,@output)=$glass->execute("env"); =back =over 4 =item $glass->parse($COMMAND); Works like execute, however it returns the command it would send to the router, but doesn't actually send it. =back =over 4 =item $glass->error([-clear|@LIST]); Sets or returns one or more error messages. If the first arguement in the list is "-clear", it will erase the list of errors. =back =head1 HIDDEN METHODS The following methods are part of the LG class, but implementors are not expected to use them. =over 4 =item _loadDriver() Loads the driver defined in the router data structure =back =over 4 =item _driver() Returns the object pointer to the router driver =back =over 4 =item _cacheFile Returns a parsed filename for the cachefile, which is the name of the command followed by two dashes and the hostname of the remote router =back =over 4 =item _cacheOK Returns a boolean flag indicating whether or not we could use cached data instead of accessing the remote router =back =over 4 =item _readCache Reads a cached output file =back =over 4 =item _writeCache Writes output to a cache file =back irectory) -ttl (time to live in secs) sub cache { my ($self,%args)=@_; if (%args) { if ($args{"-directory"}) { # determine if directory is safe if (-d $args{"-directory"}) { Router/LG/Makefile.PL010064400010200000062000000003470712617622200160370ustar00cjosephsysengr00000400000366use ExtUtils::MakeMaker; # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. WriteMakefile( 'NAME' => 'Router::LG', 'VERSION_FROM' => 'LG.pm', # finds $VERSION ); Router/LG/test.pl010064400010200000062000000012170712617622200153760ustar00cjosephsysengr00000400000366# Before `make install' is performed this script should be runnable with # `make test'. After `make install' it should work as `perl test.pl' ######################### We start with some black magic to print on failure. # Change 1..1 below to 1..last_test_to_print . # (It may become useful if the test is moved to ./t subdirectory.) BEGIN { $| = 1; print "1..1\n"; } END {print "not ok 1\n" unless $loaded;} use Router::LG; $loaded = 1; print "ok 1\n"; ######################### End of black magic. # Insert your test code below (better if it prints "ok 13" # (correspondingly "not ok 13") depending on the success of chunk 13 # of the test code): Router/LG/Changes010064400010200000062000000001500712644373500153560ustar00cjosephsysengr00000400000366Revision history for Perl extension Router::LG. 0.98 Tue Jun 27 14:12:18 2000 - First public release Router/LG/MANIFEST010064400010200000062000000001240712644616000152100ustar00cjosephsysengr00000400000366Changes LG.pm MANIFEST Makefile.PL test.pl Routers.txt README Todo.txt Security.txt Router/LG/Juniper/004075500010200000062000000000000712621541100154725ustar00cjosephsysengr00000400000366Router/LG/Juniper/Juniper.pm010064400010200000062000000122420713140477400174520ustar00cjosephsysengr00000400000366#!/usr/local/bin/perl # # LG::Juniper # Juniper LG Driver # Chris Josephes 20000306 # # # Includes # # # Package Definition # package Router::LG::Juniper; # # Global Variables # # Default values for SSH communication $SSH="/usr/local/bin/ssh"; $SSHENC="3des"; # Command Structure %Command=( "bgp" => { -command => "show route protocol bgp aspath-regex !a terse", -label => "Show Route Protocl BGP Aspath-Regex (aspath) Terse", }, "routes" => { -command => "show route !i terse", -label => "Show Route (ip) Terse", }, "traceroute" => { -command => "traceroute !ih", -label => "Traceroute (ip/hostname)", }, "ping" => { -command => "ping count 3 !ih", -label => "Ping Count 5 (ip/hostname)", }, ); # Methods %Methods=( "ssh" => { -command => "_runSsh", -default => 1, }, ); # Version Data $VERSION=0.90; # # Subroutines/Methods # sub new { my ($caller)=@_; my ($object)={}; my ($loop); bless ($object); $object->caller($caller); foreach $loop (keys(%Command)) { $object->{cmd}->{$loop}=$Command{$loop}; } return($object); } sub version { return($VERSION); } sub caller { my ($self,$caller)=@_; if ($caller) { $self->{caller}=$caller; } return($self->{caller}); } sub cachable { my ($self,$command)=@_; return($self->{cmd}->{$command}->{"-cache"}); } sub command { my ($self,$command,@args)=@_; my ($loop,%ha); if (!defined($self->{cmd}->{$command}) && !(@args)) { $self->{caller}->error("Undefined command"); } if (@args) { if ($args[0] eq "-remove") { delete($self->{cmd}->{$command}); } else { (%ha)=(@args); foreach $loop (keys(%ha)) { $self->{cmd}->{$command}->{$loop}=$ha{$loop}; } } } return(%{$self->{cmd}->{$command}}); } sub commands { my ($self)=@_; return(keys(%{$self->{cmd}})); } sub exec { my ($self,$command)=@_; my ($router,$commandstring,$caller); $caller=$self->caller(); if ($self->{cmd}->{$command}) { (@params)=$caller->parameters(); ($commandstring)=$self->_compile($command,@params); $router=$caller->router(); (@output)=$self->run($router,$commandstring); return(@output); } else { $caller->error("Undefined command ($command)"); return(undef); } } sub parse { my ($self,$command)=@_; my ($commndstring,$caller,@params); if ($self->{cmd}->{$command}) { $caller=$self->caller(); (@params)=$caller->parameters(); ($commandstring)=$self->_compile($command,@params); return($commandstring); } return(undef); } sub run { my ($self,$router,$commandstring)=@_; my ($method,$loop,@output); $method=$router->{"-method"}; unless ($Methods{$method}) { foreach $loop (keys(%Methods)) { if ($Methods{$loop}->{"-default"}) { $method=$loop; last; } } } if ($method) { (@output)=&{$Methods{$method}->{"-command"}} ($self,$router,$commandstring); } else { return(undef); } return(@output); } sub _compile { my ($self,$command,@params)=@_; my ($cmd,$left,$right,$mid,$arg); $cmd=$self->{cmd}->{$command}->{-command}; while ($cmd=~/[%!][aih]+/) { $left=$`; $right=$'; $mid=$&; $arg=shift(@params); if (!$arg && $mid=~/^!/) { $caller=$self->caller(); $caller->error("Not enough parameters"); return(undef); } #$arg=~s/$AcceptableInput//g; $arg=~s/[^\w\d\/.*\s\-]//g; $arg="\\".chr(34).$arg."\\".chr(34); $cmd=$left.$arg.$right; } # Need to add no-more to prevent CLI scroll-locking $cmd=$cmd."| no-more"; return($cmd); } sub _runSsh { my ($self,$router,$commandstring)=@_; my ($sshc,$enc,$hostargs,$host,@output); $hostargs=$router->{"-args"}; $host=$router->{"-hostname"}; $sshc=$hostargs->{"-sshCommand"} || $SSH; $enc="-c " . ($hostargs->{"-sshEncryption"} || $SSHENC); open (S, "$sshc $enc $host \"$commandstring\"|") || return(undef); while ($x=) { push(@output,$x); } close(S); return(@output); } # # Main Program Block # # # Exit Block # 1; __END__ # # POD Documentation # =head1 NAME Router::LG::Juniper - Looking Glass driver for Juniper routers =head1 SYNOPSIS use Router::LG; $glass=Router::LG->new(); $router={ -hostname => "core.router.isp.node", -class => "Juniper", -args => { -sshCommand => "/opt/ssh/bin/ssh", }, }; $glass->router($router); =head1 DESCRIPTION The Router::LG::Juniper class is a driver class for LG.pm specific to Juniper Routers. Implementors of LG.pm should not need to call methods on this class directly, as the Router::LG module can be used as the primary interface. =head1 REMOTE ACCESS METHODS Router::LG::Juniper uses the SSH protocol to access the remote router. Currently, this can only be achieved by making a call to the "ssh" client command. It assumes that the full path is "/usr/local/bin/ssh", but this can be altered by specifying the -sshCommand arguement. Don't let end users specify the values that can be set for this arguement. =head1 COMMANDS The following commands are defined by default: =over 4 bgp show route protocol bgp aspath-regex !a terse routes show route !i terse traceroute traceroute !ih ping ping count 3 !ih Read the distribution documentation for information on the command data format. ,@params); if ($self->{cmd}->{$command}) { $caller=$self->caller(); (@params)=$caller->parameters(); ($commandstring)=$self->_compile($command,@params); return($commandstring); } return(undef); } sub run { my ($self,$router,$commandstring)=@_; my ($method,$loop,@output); $method=$router->{"-method"}; unless ($Methods{$method}) { foreacRouter/LG/Juniper/Makefile.PL010064400010200000062000000003650712617654200174600ustar00cjosephsysengr00000400000366use ExtUtils::MakeMaker; # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. WriteMakefile( 'NAME' => 'Router::LG::Juniper', 'VERSION_FROM' => 'Juniper.pm', # finds $VERSION ); Router/LG/Juniper/test.pl010064400010200000062000000012300712617654200170120ustar00cjosephsysengr00000400000366# Before `make install' is performed this script should be runnable with # `make test'. After `make install' it should work as `perl test.pl' ######################### We start with some black magic to print on failure. # Change 1..1 below to 1..last_test_to_print . # (It may become useful if the test is moved to ./t subdirectory.) BEGIN { $| = 1; print "1..1\n"; } END {print "not ok 1\n" unless $loaded;} use Router::LG::Juniper; $loaded = 1; print "ok 1\n"; ######################### End of black magic. # Insert your test code below (better if it prints "ok 13" # (correspondingly "not ok 13") depending on the success of chunk 13 # of the test code): Router/LG/Juniper/Changes010064400010200000062000000001610712644627000167710ustar00cjosephsysengr00000400000366Revision history for Perl extension Router::LG::Juniper. 0.01 Tue Jun 27 14:15:46 2000 - First public release Router/LG/Juniper/MANIFEST010064400010200000062000000000600712617654200166270ustar00cjosephsysengr00000400000366Changes Juniper.pm MANIFEST Makefile.PL test.pl Router/LG/Juniper/Makefile010064400010200000062000000275350712621541100171430ustar00cjosephsysengr00000400000366# This Makefile is for the Router::LG::Juniper extension to perl. # # It was generated automatically by MakeMaker version # 5.4302 (Revision: 1.222) from the contents of # Makefile.PL. Don't edit this file, edit Makefile.PL instead. # # ANY CHANGES MADE HERE WILL BE LOST! # # MakeMaker ARGV: () # # MakeMaker Parameters: # NAME => q[Router::LG::Juniper] # VERSION_FROM => q[Juniper.pm] # --- MakeMaker post_initialize section: # --- MakeMaker const_config section: # These definitions are from config.sh (via /usr/local/lib/perl5/5.00503/sun4-solaris/Config.pm) # They may have been overridden via Makefile.PL or on the command line AR = ar CC = gcc CCCDLFLAGS = -fPIC CCDLFLAGS = DLEXT = so DLSRC = dl_dlopen.xs LD = gcc LDDLFLAGS = -G -L/usr/local/lib LDFLAGS = -L/usr/local/lib LIBC = /lib/libc.so LIB_EXT = .a OBJ_EXT = .o OSNAME = solaris OSVERS = 2.7 RANLIB = : SO = so EXE_EXT = # --- MakeMaker constants section: AR_STATIC_ARGS = cr NAME = Router::LG::Juniper DISTNAME = Router-LG-Juniper NAME_SYM = Router_LG_Juniper VERSION = 0.9 VERSION_SYM = 0_9 XS_VERSION = 0.9 INST_BIN = ../blib/bin INST_EXE = ../blib/script INST_LIB = ../blib/lib INST_ARCHLIB = ../blib/arch INST_SCRIPT = ../blib/script PREFIX = /usr/local INSTALLDIRS = site INSTALLPRIVLIB = $(PREFIX)/lib/perl5/5.00503 INSTALLARCHLIB = $(PREFIX)/lib/perl5/5.00503/sun4-solaris INSTALLSITELIB = $(PREFIX)/lib/perl5/site_perl/5.005 INSTALLSITEARCH = $(PREFIX)/lib/perl5/site_perl/5.005/sun4-solaris INSTALLBIN = $(PREFIX)/bin INSTALLSCRIPT = $(PREFIX)/bin PERL_LIB = /usr/local/lib/perl5/5.00503 PERL_ARCHLIB = /usr/local/lib/perl5/5.00503/sun4-solaris SITELIBEXP = /usr/local/lib/perl5/site_perl/5.005 SITEARCHEXP = /usr/local/lib/perl5/site_perl/5.005/sun4-solaris LIBPERL_A = libperl.a FIRST_MAKEFILE = Makefile MAKE_APERL_FILE = Makefile.aperl PERLMAINCC = $(CC) PERL_INC = /usr/local/lib/perl5/5.00503/sun4-solaris/CORE PERL = /usr/local/bin/perl FULLPERL = /usr/local/bin/perl VERSION_MACRO = VERSION DEFINE_VERSION = -D$(VERSION_MACRO)=\"$(VERSION)\" XS_VERSION_MACRO = XS_VERSION XS_DEFINE_VERSION = -D$(XS_VERSION_MACRO)=\"$(XS_VERSION)\" MAKEMAKER = /usr/local/lib/perl5/5.00503/ExtUtils/MakeMaker.pm MM_VERSION = 5.4302 # FULLEXT = Pathname for extension directory (eg Foo/Bar/Oracle). # BASEEXT = Basename part of FULLEXT. May be just equal FULLEXT. (eg Oracle) # ROOTEXT = Directory part of FULLEXT with leading slash (eg /DBD) !!! Deprecated from MM 5.32 !!! # PARENT_NAME = NAME without BASEEXT and no trailing :: (eg Foo::Bar) # DLBASE = Basename part of dynamic library. May be just equal BASEEXT. FULLEXT = Router/LG/Juniper BASEEXT = Juniper PARENT_NAME = Router::LG DLBASE = $(BASEEXT) VERSION_FROM = Juniper.pm OBJECT = LDFROM = $(OBJECT) LINKTYPE = dynamic # Handy lists of source code files: XS_FILES= C_FILES = O_FILES = H_FILES = MAN1PODS = MAN3PODS = Juniper.pm INST_MAN1DIR = ../blib/man1 INSTALLMAN1DIR = /usr/local/man/man1 MAN1EXT = 1 INST_MAN3DIR = ../blib/man3 INSTALLMAN3DIR = /usr/local/lib/perl5/5.00503/man/man3 MAN3EXT = 3 PERM_RW = 644 PERM_RWX = 755 # work around a famous dec-osf make(1) feature(?): makemakerdflt: all .SUFFIXES: .xs .c .C .cpp .cxx .cc $(OBJ_EXT) # Nick wanted to get rid of .PRECIOUS. I don't remember why. I seem to recall, that # some make implementations will delete the Makefile when we rebuild it. Because # we call false(1) when we rebuild it. So make(1) is not completely wrong when it # does so. Our milage may vary. # .PRECIOUS: Makefile # seems to be not necessary anymore .PHONY: all config static dynamic test linkext manifest # Where is the Config information that we are using/depend on CONFIGDEP = $(PERL_ARCHLIB)/Config.pm $(PERL_INC)/config.h # Where to put things: INST_LIBDIR = $(INST_LIB)/Router/LG INST_ARCHLIBDIR = $(INST_ARCHLIB)/Router/LG INST_AUTODIR = $(INST_LIB)/auto/$(FULLEXT) INST_ARCHAUTODIR = $(INST_ARCHLIB)/auto/$(FULLEXT) INST_STATIC = INST_DYNAMIC = INST_BOOT = EXPORT_LIST = PERL_ARCHIVE = TO_INST_PM = Juniper.pm PM_TO_BLIB = Juniper.pm \ $(INST_LIBDIR)/Juniper.pm # --- MakeMaker tool_autosplit section: # Usage: $(AUTOSPLITFILE) FileToSplit AutoDirToSplitInto AUTOSPLITFILE = $(PERL) "-I$(PERL_ARCHLIB)" "-I$(PERL_LIB)" -e 'use AutoSplit;autosplit($$ARGV[0], $$ARGV[1], 0, 1, 1) ;' # --- MakeMaker tool_xsubpp section: # --- MakeMaker tools_other section: SHELL = /bin/sh CHMOD = chmod CP = cp LD = gcc MV = mv NOOP = $(SHELL) -c true RM_F = rm -f RM_RF = rm -rf TEST_F = test -f TOUCH = touch UMASK_NULL = umask 0 DEV_NULL = > /dev/null 2>&1 # The following is a portable way to say mkdir -p # To see which directories are created, change the if 0 to if 1 MKPATH = $(PERL) -I$(PERL_ARCHLIB) -I$(PERL_LIB) -MExtUtils::Command -e mkpath # This helps us to minimize the effect of the .exists files A yet # better solution would be to have a stable file in the perl # distribution with a timestamp of zero. But this solution doesn't # need any changes to the core distribution and works with older perls EQUALIZE_TIMESTAMP = $(PERL) -I$(PERL_ARCHLIB) -I$(PERL_LIB) -MExtUtils::Command -e eqtime # --- MakeMaker dist section skipped. # --- MakeMaker macro section: # --- MakeMaker depend section: # --- MakeMaker cflags section: # --- MakeMaker const_loadlibs section: # --- MakeMaker const_cccmd section: # --- MakeMaker post_constants section: # --- MakeMaker pasthru section: PASTHRU = LIB="$(LIB)"\ LIBPERL_A="$(LIBPERL_A)"\ LINKTYPE="$(LINKTYPE)"\ PREFIX="$(PREFIX)"\ OPTIMIZE="$(OPTIMIZE)" # --- MakeMaker c_o section: # --- MakeMaker xs_c section: # --- MakeMaker xs_o section: # --- MakeMaker top_targets section: #all :: config $(INST_PM) subdirs linkext manifypods all :: pure_all manifypods @$(NOOP) pure_all :: config pm_to_blib subdirs linkext @$(NOOP) subdirs :: $(MYEXTLIB) @$(NOOP) config :: Makefile $(INST_LIBDIR)/.exists @$(NOOP) config :: $(INST_ARCHAUTODIR)/.exists @$(NOOP) config :: $(INST_AUTODIR)/.exists @$(NOOP) $(INST_AUTODIR)/.exists :: /usr/local/lib/perl5/5.00503/sun4-solaris/CORE/perl.h @$(MKPATH) $(INST_AUTODIR) @$(EQUALIZE_TIMESTAMP) /usr/local/lib/perl5/5.00503/sun4-solaris/CORE/perl.h $(INST_AUTODIR)/.exists -@$(CHMOD) $(PERM_RWX) $(INST_AUTODIR) $(INST_LIBDIR)/.exists :: /usr/local/lib/perl5/5.00503/sun4-solaris/CORE/perl.h @$(MKPATH) $(INST_LIBDIR) @$(EQUALIZE_TIMESTAMP) /usr/local/lib/perl5/5.00503/sun4-solaris/CORE/perl.h $(INST_LIBDIR)/.exists -@$(CHMOD) $(PERM_RWX) $(INST_LIBDIR) $(INST_ARCHAUTODIR)/.exists :: /usr/local/lib/perl5/5.00503/sun4-solaris/CORE/perl.h @$(MKPATH) $(INST_ARCHAUTODIR) @$(EQUALIZE_TIMESTAMP) /usr/local/lib/perl5/5.00503/sun4-solaris/CORE/perl.h $(INST_ARCHAUTODIR)/.exists -@$(CHMOD) $(PERM_RWX) $(INST_ARCHAUTODIR) config :: $(INST_MAN3DIR)/.exists @$(NOOP) $(INST_MAN3DIR)/.exists :: /usr/local/lib/perl5/5.00503/sun4-solaris/CORE/perl.h @$(MKPATH) $(INST_MAN3DIR) @$(EQUALIZE_TIMESTAMP) /usr/local/lib/perl5/5.00503/sun4-solaris/CORE/perl.h $(INST_MAN3DIR)/.exists -@$(CHMOD) $(PERM_RWX) $(INST_MAN3DIR) help: perldoc ExtUtils::MakeMaker Version_check: @$(PERL) -I$(PERL_ARCHLIB) -I$(PERL_LIB) \ -MExtUtils::MakeMaker=Version_check \ -e "Version_check('$(MM_VERSION)')" # --- MakeMaker linkext section: linkext :: $(LINKTYPE) @$(NOOP) # --- MakeMaker dlsyms section: # --- MakeMaker dynamic section: ## $(INST_PM) has been moved to the all: target. ## It remains here for awhile to allow for old usage: "make dynamic" #dynamic :: Makefile $(INST_DYNAMIC) $(INST_BOOT) $(INST_PM) dynamic :: Makefile $(INST_DYNAMIC) $(INST_BOOT) @$(NOOP) # --- MakeMaker dynamic_bs section: BOOTSTRAP = # --- MakeMaker dynamic_lib section: # --- MakeMaker static section: ## $(INST_PM) has been moved to the all: target. ## It remains here for awhile to allow for old usage: "make static" #static :: Makefile $(INST_STATIC) $(INST_PM) static :: Makefile $(INST_STATIC) @$(NOOP) # --- MakeMaker static_lib section: # --- MakeMaker manifypods section: POD2MAN_EXE = /usr/local/bin/pod2man POD2MAN = $(PERL) -we '%m=@ARGV;for (keys %m){' \ -e 'next if -e $$m{$$_} && -M $$m{$$_} < -M $$_ && -M $$m{$$_} < -M "Makefile";' \ -e 'print "Manifying $$m{$$_}\n";' \ -e 'system(qq[$$^X ].q["-I$(PERL_ARCHLIB)" "-I$(PERL_LIB)" $(POD2MAN_EXE) ].qq[$$_>$$m{$$_}])==0 or warn "Couldn\047t install $$m{$$_}\n";' \ -e 'chmod(oct($(PERM_RW))), $$m{$$_} or warn "chmod $(PERM_RW) $$m{$$_}: $$!\n";}' manifypods : pure_all Juniper.pm @$(POD2MAN) \ Juniper.pm \ $(INST_MAN3DIR)/Router::LG::Juniper.$(MAN3EXT) # --- MakeMaker processPL section: # --- MakeMaker installbin section: # --- MakeMaker subdirs section: # none # --- MakeMaker clean section: # Delete temporary files but do not touch installed files. We don't delete # the Makefile here so a later make realclean still has a makefile to use. clean :: -rm -rf ./blib $(MAKE_APERL_FILE) $(INST_ARCHAUTODIR)/extralibs.all perlmain.c mon.out core so_locations pm_to_blib *~ */*~ */*/*~ *$(OBJ_EXT) *$(LIB_EXT) perl.exe $(BOOTSTRAP) $(BASEEXT).bso $(BASEEXT).def $(BASEEXT).exp -mv Makefile Makefile.old $(DEV_NULL) # --- MakeMaker realclean section: # Delete temporary files (via clean) and also delete installed files realclean purge :: clean rm -rf $(INST_AUTODIR) $(INST_ARCHAUTODIR) rm -f $(INST_LIBDIR)/Juniper.pm rm -rf Makefile Makefile.old # --- MakeMaker dist_basics section skipped. # --- MakeMaker dist_core section skipped. # --- MakeMaker dist_dir section skipped. # --- MakeMaker dist_test section skipped. # --- MakeMaker dist_ci section skipped. # --- MakeMaker install section skipped. # --- MakeMaker force section: # Phony target to force checking subdirectories. FORCE: @$(NOOP) # --- MakeMaker perldepend section: # --- MakeMaker makefile section: # We take a very conservative approach here, but it\'s worth it. # We move Makefile to Makefile.old here to avoid gnu make looping. Makefile : Makefile.PL $(CONFIGDEP) @echo "Makefile out-of-date with respect to $?" @echo "Cleaning current config before rebuilding Makefile..." -@$(RM_F) Makefile.old -@$(MV) Makefile Makefile.old -$(MAKE) -f Makefile.old clean $(DEV_NULL) || $(NOOP) $(PERL) "-I$(PERL_ARCHLIB)" "-I$(PERL_LIB)" Makefile.PL @echo "==> Your Makefile has been rebuilt. <==" @echo "==> Please rerun the make command. <==" false # To change behavior to :: would be nice, but would break Tk b9.02 # so you find such a warning below the dist target. #Makefile :: $(VERSION_FROM) # @echo "Warning: Makefile possibly out of date with $(VERSION_FROM)" # --- MakeMaker staticmake section: # --- MakeMaker makeaperl section --- MAP_TARGET = ../perl FULLPERL = /usr/local/bin/perl # --- MakeMaker test section: TEST_VERBOSE=0 TEST_TYPE=test_$(LINKTYPE) TEST_FILE = test.pl TEST_FILES = TESTDB_SW = -d testdb :: testdb_$(LINKTYPE) test :: $(TEST_TYPE) test_dynamic :: pure_all PERL_DL_NONLAZY=1 $(FULLPERL) -I$(INST_ARCHLIB) -I$(INST_LIB) -I$(PERL_ARCHLIB) -I$(PERL_LIB) $(TEST_FILE) testdb_dynamic :: pure_all PERL_DL_NONLAZY=1 $(FULLPERL) $(TESTDB_SW) -I$(INST_ARCHLIB) -I$(INST_LIB) -I$(PERL_ARCHLIB) -I$(PERL_LIB) $(TEST_FILE) test_ : test_dynamic test_static :: test_dynamic testdb_static :: testdb_dynamic # --- MakeMaker ppd section: # Creates a PPD (Perl Package Description) for a binary distribution. ppd: @$(PERL) -e "print qq{\n}. qq{\tRouter-LG-Juniper\n}. qq{\t\n}. qq{\t\n}. qq{\t\n}. qq{\t\t\n}. qq{\t\t\n}. qq{\t\t\n}. qq{\t\n}. qq{\n}" > Router-LG-Juniper.ppd # --- MakeMaker pm_to_blib section: pm_to_blib: $(TO_INST_PM) @$(PERL) "-I$(INST_ARCHLIB)" "-I$(INST_LIB)" \ "-I$(PERL_ARCHLIB)" "-I$(PERL_LIB)" -MExtUtils::Install \ -e "pm_to_blib({qw{$(PM_TO_BLIB)}},'$(INST_LIB)/auto')" @$(TOUCH) $@ # --- MakeMaker selfdocument section: # --- MakeMaker postamble section: # End. Router/LG/Cisco/004075500010200000062000000000000712621541100151165ustar00cjosephsysengr00000400000366Router/LG/Cisco/Cisco.pm010064400010200000062000000204250713140473100165150ustar00cjosephsysengr00000400000366#!/usr/local/bin/perl # Router::LG::Cisco # # Package Definition # package Router::LG::Cisco; # # Includes # use IO::Socket; # # Global Variables # # Command Structure of available Commands %Command=( "acl" => { -command => "sh access-list 115", -label => "Show Access List 115", -cache => 1, }, "pre" => { -command => "sh ip prefix-list UPSTREAM", -label => "Show IP Prefix List UPSTREAM", -cache => 1, }, "bgp" => { -command => "sh ip bgp %ia", -label => "Show IP BGP (ip/as regex)", -cache => 1, }, "bgpdp" => { -command => "sh ip bgp dampened-paths", -label => "Show IP BGP Dampened-Paths", }, "bgpfs" => { -command => "sh ip bgp flap-statistics %ia", -label => "Show IP BGP Flap-Statistics (ip/as regex)", -cache => 1, }, "bgps" => { -command => "sh ip bgp summary", -label => "Show IP BGP Summary", -cache => 1, }, "env" => { -command => "sh enviro all", -label => "Show Environment All", -cache => 1, }, "mrs" => { -command => "sh ip mroute summary", -label => "Show IP Mroute Summary", -cache => 1, }, "ping" => { -command => "ping !ih", -label => "Ping (hostname/ip)", }, "traceroute" => { -command => "traceroute !ih", -label => "Traceroute (hostname/ip)", }, "bgpnar" => { -command => "sh ip bgp neighbors !i advertised-routes", -label => "Show IP BGP Neighbors (ip) Advertised-Routes", }, ); # Available execution methods %Methods=( "rsh" => { -command => "_runRsh", -default => 1, }, ); # Input that should be filtered #$AcceptableInput="[^A-Za-z0-9*_.\-\s]"; #$AcceptableInput="^[^\d\w*.\s\-]\$"; # Version Information $VERSION=0.9; # # Subroutines # # # Constructor Method # # Instance method sub new { my ($caller)=@_; my ($object)={}; my ($loop); bless ($object); $object->caller($caller); foreach $loop (keys(%Command)) { $object->{cmd}->{$loop}=$Command{$loop}; } return($object); } sub version { return($VERSION); } sub commands { my ($self)=@_; return(keys(%{$self->{cmd}})); } sub command { my ($self,$command,@args)=@_; my ($loop,%ha); if (!defined($self->{cmd}->{$command}) && !(@args)) { # User wants data on a command that does not exist # Technically this code is unnecessary since it would # return undef anyways $self->{caller}->error("Undefined command ($command)"); return(undef); } if (@args) { if ($args[0] eq "-remove") { delete($self->{cmd}->{$command}); } else { (%ha)=(@args); foreach $loop (keys(%ha)) { $self->{cmd}->{$command}->{$loop}=$ha{$loop}; } } } return(%{$self->{cmd}->{$command}}); } # Returns whether or not the command is cachable sub cachable { my ($self,$command)=@_; return($self->{cmd}->{$command}->{"-cache"}); } sub methods { return(keys(%Methods)); } sub caller { my ($self,$parent)=@_; if ($parent) { $self->{caller}=$parent; } return($self->{caller}); } sub exec { my ($self,$command)=@_; my ($router,$commandstring,$caller); #print("The command ($command) was called\n"); # See if the command exists. If so, run it $caller=$self->caller(); if ($self->{cmd}->{$command}) { (@params)=$caller->parameters(); ($commandstring)=$self->_compile($command,@params); $router=$caller->router(); (@output)=$self->run($router,$commandstring); # (desired) return(@output); } else { $caller->error("Undefined command ($command)"); return(undef); } } sub parse { my ($self,$command)=@_; my ($commandstring,$caller); if ($self->{cmd}->{$command}) { $caller=$self->caller(); $caller->error("Test error"); (@params)=$caller->parameters(); ($commandstring)=$self->_compile($command,@params); return($commandstring); } return(undef); } sub run { my ($self,$router,$commandstring)=@_; my ($method,$loop,@output); $method=$router->{"-method"}; unless ($Methods{$method}) { foreach $loop (keys(%Methods)) { if ($Methods{$loop}->{"-default"}) { $method=$loop; last; } } } if ($method) { (@output)=&{$Methods{$method}->{"-command"}} ($self,$router,$commandstring); } else { return(undef); } return(@output); } # # Hidden Methods # sub _compile { my ($self,$command,@params)=@_; my ($cmd,$left,$right,$mid,$arg); $cmd=$self->{cmd}->{$command}->{-command}; while ($cmd=~/[%!][aih]+/) { $left=$`; $right=$'; $mid=$&; $arg=shift(@params); if (!$arg && $mid=~/^!/) { $caller=$self->caller(); $caller->error("Not enough parameters"); return(undef); } $arg=~s/[^\w\d.*\s\-]//g; $arg=~s/(^\s+|\s+$)//g; if ($arg=~/reg.*\s+/) { (undef,$arg)=split(/\s+/,$arg); $arg="regex $arg"; } $cmd=$left.$arg.$right; } return($cmd); } # _runRSH # Use the RSH protcol to access the router sub _runRsh { my ($self,$router,$commandstring)=@_; my ($hostargs,$caller); $hostargs=$router->{"-args"}; unless ($hostargs->{"-luser"} && $hostargs->{"-ruser"}) { $caller=$self->caller(); $caller->error("Need Local user and Remote user defined"); return(undef); } my ($socket,$result,@output); $socket=IO::Socket::INET-> new(PeerAddr => "$router->{-hostname}:514", Proto => "tcp", Timeout => 60); unless ($socket) { return(undef); } #print("Socket open\n"); $socket->syswrite("0\0",2); #print("LUSER: $hostargs->{'-luser'} RUSER: $hostargs->{'-ruser'}\n"); #print("CMD: $commandstring\n"); $socket->syswrite($hostargs->{"-luser"}."\0", (length($hostargs->{"-luser"})+1)); $socket->syswrite($hostargs->{"-ruser"}."\0", (length($hostargs->{"-ruser"})+1)); $socket->syswrite($commandstring."\0", (length($commandstring)+1)); $result=$socket->sysread($output,1); (@output)=$socket->getlines(); $socket->close(); return(@output); } # # Exit Block # 1; __END__ =head1 NAME Router::LG::Cisco - LG Driver for Cisco Routers =head1 SYNOPSIS use Router::LG; $glass=LG->new(); $router={ -hostname => "core.router.isp.node", -class => "Cisco", -args => { -luser => "local_user", -ruser => "remote_user", }, }; $glass->router($router); =head1 DESCRIPTION The Router::LG::Cisco class is a driver class for LG.pm specific to Cisco Routers. Implementors of LG.pm should not need to call methods on this class directly, as the Router::LG.pm module is the primary interface. This document only serves as an overview of the class. For more information on router drivers, check the Router::LG::Driver documentation. =head1 REMOTE ACCESS METHODS Router::LG::Cisco uses the RSH protocol to access the remote router. The RSH protocol requires that a connecting client pass a local username, and a remote username, followed by the command to send. The server will then return the output from the execution of the passed command. The local username is not authenticated in any way, but it needs to be one that the Cisco router is configured to accept. The final program does not need to run as this particular username, nor does it even need to exist on the host running the program. This module uses IO::Socket to make the connection to the router. No "rsh" command is required on the local host. Technically, the RSH protocol requires that clients connect from a port in the < 1024 range; however, Cisco equipment does not seem to care. =head1 CISCO SETUP The following is a recommended setup for a Cisco router to allow RSH access: ip rcmd rsh-enable ip rcmd remote-host client_user a.b.c.d server_user Please check your Cisco documentation for more information. =head1 COMMANDS The following commands are defined by default: =over 4 acl* sh access-list 115 pre* sh ip prefix-list UPSTREAM bgp* sh ip bgp %ia bgpdp sh ip bgp dampened-paths bgpfs sh ip bgp flap-statistics bgps* sh ip bgp summary env* sh enviro all mrs sh ip mroute summary ping ping !ih traceroute traceroute !ih bgpnar sh ip bgp neighbors !i advertised-routes =back Commands with an asterick are cached whenever possible. See the Router::LG::Driver documentation for information on the command data format. =head1 REMOTE ACCESS METHODS Router::LG::Cisco supports only one method of remote access: rsh. It is the default choice if the -method parameter of a router definition is undefined. The arguements needed for rsh access include a local username and a remote username. =head1 COMMAND DATA STRUCTURE Read the "Routers.txt" file from the Router::LG distribution bundle for more information on the structure of the command variable. Router/LG/Cisco/Makefile.PL010064400010200000062000000003610712617654700171050ustar00cjosephsysengr00000400000366use ExtUtils::MakeMaker; # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. WriteMakefile( 'NAME' => 'Router::LG::Cisco', 'VERSION_FROM' => 'Cisco.pm', # finds $VERSION ); Router/LG/Cisco/test.pl010064400010200000062000000012260712617654700164500ustar00cjosephsysengr00000400000366# Before `make install' is performed this script should be runnable with # `make test'. After `make install' it should work as `perl test.pl' ######################### We start with some black magic to print on failure. # Change 1..1 below to 1..last_test_to_print . # (It may become useful if the test is moved to ./t subdirectory.) BEGIN { $| = 1; print "1..1\n"; } END {print "not ok 1\n" unless $loaded;} use Router::LG::Cisco; $loaded = 1; print "ok 1\n"; ######################### End of black magic. # Insert your test code below (better if it prints "ok 13" # (correspondingly "not ok 13") depending on the success of chunk 13 # of the test code): Router/LG/Cisco/Changes010064400010200000062000000001570712644625200164220ustar00cjosephsysengr00000400000366Revision history for Perl extension Router::LG::Cisco. 0.9 Tue Jun 27 14:15:51 2000 - First public release Router/LG/Cisco/MANIFEST010064400010200000062000000000560712617654700162650ustar00cjosephsysengr00000400000366Changes Cisco.pm MANIFEST Makefile.PL test.pl Router/LG/Cisco/Makefile010064400010200000062000000274650712621541100165710ustar00cjosephsysengr00000400000366# This Makefile is for the Router::LG::Cisco extension to perl. # # It was generated automatically by MakeMaker version # 5.4302 (Revision: 1.222) from the contents of # Makefile.PL. Don't edit this file, edit Makefile.PL instead. # # ANY CHANGES MADE HERE WILL BE LOST! # # MakeMaker ARGV: () # # MakeMaker Parameters: # NAME => q[Router::LG::Cisco] # VERSION_FROM => q[Cisco.pm] # --- MakeMaker post_initialize section: # --- MakeMaker const_config section: # These definitions are from config.sh (via /usr/local/lib/perl5/5.00503/sun4-solaris/Config.pm) # They may have been overridden via Makefile.PL or on the command line AR = ar CC = gcc CCCDLFLAGS = -fPIC CCDLFLAGS = DLEXT = so DLSRC = dl_dlopen.xs LD = gcc LDDLFLAGS = -G -L/usr/local/lib LDFLAGS = -L/usr/local/lib LIBC = /lib/libc.so LIB_EXT = .a OBJ_EXT = .o OSNAME = solaris OSVERS = 2.7 RANLIB = : SO = so EXE_EXT = # --- MakeMaker constants section: AR_STATIC_ARGS = cr NAME = Router::LG::Cisco DISTNAME = Router-LG-Cisco NAME_SYM = Router_LG_Cisco VERSION = 0.9 VERSION_SYM = 0_9 XS_VERSION = 0.9 INST_BIN = ../blib/bin INST_EXE = ../blib/script INST_LIB = ../blib/lib INST_ARCHLIB = ../blib/arch INST_SCRIPT = ../blib/script PREFIX = /usr/local INSTALLDIRS = site INSTALLPRIVLIB = $(PREFIX)/lib/perl5/5.00503 INSTALLARCHLIB = $(PREFIX)/lib/perl5/5.00503/sun4-solaris INSTALLSITELIB = $(PREFIX)/lib/perl5/site_perl/5.005 INSTALLSITEARCH = $(PREFIX)/lib/perl5/site_perl/5.005/sun4-solaris INSTALLBIN = $(PREFIX)/bin INSTALLSCRIPT = $(PREFIX)/bin PERL_LIB = /usr/local/lib/perl5/5.00503 PERL_ARCHLIB = /usr/local/lib/perl5/5.00503/sun4-solaris SITELIBEXP = /usr/local/lib/perl5/site_perl/5.005 SITEARCHEXP = /usr/local/lib/perl5/site_perl/5.005/sun4-solaris LIBPERL_A = libperl.a FIRST_MAKEFILE = Makefile MAKE_APERL_FILE = Makefile.aperl PERLMAINCC = $(CC) PERL_INC = /usr/local/lib/perl5/5.00503/sun4-solaris/CORE PERL = /usr/local/bin/perl FULLPERL = /usr/local/bin/perl VERSION_MACRO = VERSION DEFINE_VERSION = -D$(VERSION_MACRO)=\"$(VERSION)\" XS_VERSION_MACRO = XS_VERSION XS_DEFINE_VERSION = -D$(XS_VERSION_MACRO)=\"$(XS_VERSION)\" MAKEMAKER = /usr/local/lib/perl5/5.00503/ExtUtils/MakeMaker.pm MM_VERSION = 5.4302 # FULLEXT = Pathname for extension directory (eg Foo/Bar/Oracle). # BASEEXT = Basename part of FULLEXT. May be just equal FULLEXT. (eg Oracle) # ROOTEXT = Directory part of FULLEXT with leading slash (eg /DBD) !!! Deprecated from MM 5.32 !!! # PARENT_NAME = NAME without BASEEXT and no trailing :: (eg Foo::Bar) # DLBASE = Basename part of dynamic library. May be just equal BASEEXT. FULLEXT = Router/LG/Cisco BASEEXT = Cisco PARENT_NAME = Router::LG DLBASE = $(BASEEXT) VERSION_FROM = Cisco.pm OBJECT = LDFROM = $(OBJECT) LINKTYPE = dynamic # Handy lists of source code files: XS_FILES= C_FILES = O_FILES = H_FILES = MAN1PODS = MAN3PODS = Cisco.pm INST_MAN1DIR = ../blib/man1 INSTALLMAN1DIR = /usr/local/man/man1 MAN1EXT = 1 INST_MAN3DIR = ../blib/man3 INSTALLMAN3DIR = /usr/local/lib/perl5/5.00503/man/man3 MAN3EXT = 3 PERM_RW = 644 PERM_RWX = 755 # work around a famous dec-osf make(1) feature(?): makemakerdflt: all .SUFFIXES: .xs .c .C .cpp .cxx .cc $(OBJ_EXT) # Nick wanted to get rid of .PRECIOUS. I don't remember why. I seem to recall, that # some make implementations will delete the Makefile when we rebuild it. Because # we call false(1) when we rebuild it. So make(1) is not completely wrong when it # does so. Our milage may vary. # .PRECIOUS: Makefile # seems to be not necessary anymore .PHONY: all config static dynamic test linkext manifest # Where is the Config information that we are using/depend on CONFIGDEP = $(PERL_ARCHLIB)/Config.pm $(PERL_INC)/config.h # Where to put things: INST_LIBDIR = $(INST_LIB)/Router/LG INST_ARCHLIBDIR = $(INST_ARCHLIB)/Router/LG INST_AUTODIR = $(INST_LIB)/auto/$(FULLEXT) INST_ARCHAUTODIR = $(INST_ARCHLIB)/auto/$(FULLEXT) INST_STATIC = INST_DYNAMIC = INST_BOOT = EXPORT_LIST = PERL_ARCHIVE = TO_INST_PM = Cisco.pm PM_TO_BLIB = Cisco.pm \ $(INST_LIBDIR)/Cisco.pm # --- MakeMaker tool_autosplit section: # Usage: $(AUTOSPLITFILE) FileToSplit AutoDirToSplitInto AUTOSPLITFILE = $(PERL) "-I$(PERL_ARCHLIB)" "-I$(PERL_LIB)" -e 'use AutoSplit;autosplit($$ARGV[0], $$ARGV[1], 0, 1, 1) ;' # --- MakeMaker tool_xsubpp section: # --- MakeMaker tools_other section: SHELL = /bin/sh CHMOD = chmod CP = cp LD = gcc MV = mv NOOP = $(SHELL) -c true RM_F = rm -f RM_RF = rm -rf TEST_F = test -f TOUCH = touch UMASK_NULL = umask 0 DEV_NULL = > /dev/null 2>&1 # The following is a portable way to say mkdir -p # To see which directories are created, change the if 0 to if 1 MKPATH = $(PERL) -I$(PERL_ARCHLIB) -I$(PERL_LIB) -MExtUtils::Command -e mkpath # This helps us to minimize the effect of the .exists files A yet # better solution would be to have a stable file in the perl # distribution with a timestamp of zero. But this solution doesn't # need any changes to the core distribution and works with older perls EQUALIZE_TIMESTAMP = $(PERL) -I$(PERL_ARCHLIB) -I$(PERL_LIB) -MExtUtils::Command -e eqtime # --- MakeMaker dist section skipped. # --- MakeMaker macro section: # --- MakeMaker depend section: # --- MakeMaker cflags section: # --- MakeMaker const_loadlibs section: # --- MakeMaker const_cccmd section: # --- MakeMaker post_constants section: # --- MakeMaker pasthru section: PASTHRU = LIB="$(LIB)"\ LIBPERL_A="$(LIBPERL_A)"\ LINKTYPE="$(LINKTYPE)"\ PREFIX="$(PREFIX)"\ OPTIMIZE="$(OPTIMIZE)" # --- MakeMaker c_o section: # --- MakeMaker xs_c section: # --- MakeMaker xs_o section: # --- MakeMaker top_targets section: #all :: config $(INST_PM) subdirs linkext manifypods all :: pure_all manifypods @$(NOOP) pure_all :: config pm_to_blib subdirs linkext @$(NOOP) subdirs :: $(MYEXTLIB) @$(NOOP) config :: Makefile $(INST_LIBDIR)/.exists @$(NOOP) config :: $(INST_ARCHAUTODIR)/.exists @$(NOOP) config :: $(INST_AUTODIR)/.exists @$(NOOP) $(INST_AUTODIR)/.exists :: /usr/local/lib/perl5/5.00503/sun4-solaris/CORE/perl.h @$(MKPATH) $(INST_AUTODIR) @$(EQUALIZE_TIMESTAMP) /usr/local/lib/perl5/5.00503/sun4-solaris/CORE/perl.h $(INST_AUTODIR)/.exists -@$(CHMOD) $(PERM_RWX) $(INST_AUTODIR) $(INST_LIBDIR)/.exists :: /usr/local/lib/perl5/5.00503/sun4-solaris/CORE/perl.h @$(MKPATH) $(INST_LIBDIR) @$(EQUALIZE_TIMESTAMP) /usr/local/lib/perl5/5.00503/sun4-solaris/CORE/perl.h $(INST_LIBDIR)/.exists -@$(CHMOD) $(PERM_RWX) $(INST_LIBDIR) $(INST_ARCHAUTODIR)/.exists :: /usr/local/lib/perl5/5.00503/sun4-solaris/CORE/perl.h @$(MKPATH) $(INST_ARCHAUTODIR) @$(EQUALIZE_TIMESTAMP) /usr/local/lib/perl5/5.00503/sun4-solaris/CORE/perl.h $(INST_ARCHAUTODIR)/.exists -@$(CHMOD) $(PERM_RWX) $(INST_ARCHAUTODIR) config :: $(INST_MAN3DIR)/.exists @$(NOOP) $(INST_MAN3DIR)/.exists :: /usr/local/lib/perl5/5.00503/sun4-solaris/CORE/perl.h @$(MKPATH) $(INST_MAN3DIR) @$(EQUALIZE_TIMESTAMP) /usr/local/lib/perl5/5.00503/sun4-solaris/CORE/perl.h $(INST_MAN3DIR)/.exists -@$(CHMOD) $(PERM_RWX) $(INST_MAN3DIR) help: perldoc ExtUtils::MakeMaker Version_check: @$(PERL) -I$(PERL_ARCHLIB) -I$(PERL_LIB) \ -MExtUtils::MakeMaker=Version_check \ -e "Version_check('$(MM_VERSION)')" # --- MakeMaker linkext section: linkext :: $(LINKTYPE) @$(NOOP) # --- MakeMaker dlsyms section: # --- MakeMaker dynamic section: ## $(INST_PM) has been moved to the all: target. ## It remains here for awhile to allow for old usage: "make dynamic" #dynamic :: Makefile $(INST_DYNAMIC) $(INST_BOOT) $(INST_PM) dynamic :: Makefile $(INST_DYNAMIC) $(INST_BOOT) @$(NOOP) # --- MakeMaker dynamic_bs section: BOOTSTRAP = # --- MakeMaker dynamic_lib section: # --- MakeMaker static section: ## $(INST_PM) has been moved to the all: target. ## It remains here for awhile to allow for old usage: "make static" #static :: Makefile $(INST_STATIC) $(INST_PM) static :: Makefile $(INST_STATIC) @$(NOOP) # --- MakeMaker static_lib section: # --- MakeMaker manifypods section: POD2MAN_EXE = /usr/local/bin/pod2man POD2MAN = $(PERL) -we '%m=@ARGV;for (keys %m){' \ -e 'next if -e $$m{$$_} && -M $$m{$$_} < -M $$_ && -M $$m{$$_} < -M "Makefile";' \ -e 'print "Manifying $$m{$$_}\n";' \ -e 'system(qq[$$^X ].q["-I$(PERL_ARCHLIB)" "-I$(PERL_LIB)" $(POD2MAN_EXE) ].qq[$$_>$$m{$$_}])==0 or warn "Couldn\047t install $$m{$$_}\n";' \ -e 'chmod(oct($(PERM_RW))), $$m{$$_} or warn "chmod $(PERM_RW) $$m{$$_}: $$!\n";}' manifypods : pure_all Cisco.pm @$(POD2MAN) \ Cisco.pm \ $(INST_MAN3DIR)/Router::LG::Cisco.$(MAN3EXT) # --- MakeMaker processPL section: # --- MakeMaker installbin section: # --- MakeMaker subdirs section: # none # --- MakeMaker clean section: # Delete temporary files but do not touch installed files. We don't delete # the Makefile here so a later make realclean still has a makefile to use. clean :: -rm -rf ./blib $(MAKE_APERL_FILE) $(INST_ARCHAUTODIR)/extralibs.all perlmain.c mon.out core so_locations pm_to_blib *~ */*~ */*/*~ *$(OBJ_EXT) *$(LIB_EXT) perl.exe $(BOOTSTRAP) $(BASEEXT).bso $(BASEEXT).def $(BASEEXT).exp -mv Makefile Makefile.old $(DEV_NULL) # --- MakeMaker realclean section: # Delete temporary files (via clean) and also delete installed files realclean purge :: clean rm -rf $(INST_AUTODIR) $(INST_ARCHAUTODIR) rm -f $(INST_LIBDIR)/Cisco.pm rm -rf Makefile Makefile.old # --- MakeMaker dist_basics section skipped. # --- MakeMaker dist_core section skipped. # --- MakeMaker dist_dir section skipped. # --- MakeMaker dist_test section skipped. # --- MakeMaker dist_ci section skipped. # --- MakeMaker install section skipped. # --- MakeMaker force section: # Phony target to force checking subdirectories. FORCE: @$(NOOP) # --- MakeMaker perldepend section: # --- MakeMaker makefile section: # We take a very conservative approach here, but it\'s worth it. # We move Makefile to Makefile.old here to avoid gnu make looping. Makefile : Makefile.PL $(CONFIGDEP) @echo "Makefile out-of-date with respect to $?" @echo "Cleaning current config before rebuilding Makefile..." -@$(RM_F) Makefile.old -@$(MV) Makefile Makefile.old -$(MAKE) -f Makefile.old clean $(DEV_NULL) || $(NOOP) $(PERL) "-I$(PERL_ARCHLIB)" "-I$(PERL_LIB)" Makefile.PL @echo "==> Your Makefile has been rebuilt. <==" @echo "==> Please rerun the make command. <==" false # To change behavior to :: would be nice, but would break Tk b9.02 # so you find such a warning below the dist target. #Makefile :: $(VERSION_FROM) # @echo "Warning: Makefile possibly out of date with $(VERSION_FROM)" # --- MakeMaker staticmake section: # --- MakeMaker makeaperl section --- MAP_TARGET = ../perl FULLPERL = /usr/local/bin/perl # --- MakeMaker test section: TEST_VERBOSE=0 TEST_TYPE=test_$(LINKTYPE) TEST_FILE = test.pl TEST_FILES = TESTDB_SW = -d testdb :: testdb_$(LINKTYPE) test :: $(TEST_TYPE) test_dynamic :: pure_all PERL_DL_NONLAZY=1 $(FULLPERL) -I$(INST_ARCHLIB) -I$(INST_LIB) -I$(PERL_ARCHLIB) -I$(PERL_LIB) $(TEST_FILE) testdb_dynamic :: pure_all PERL_DL_NONLAZY=1 $(FULLPERL) $(TESTDB_SW) -I$(INST_ARCHLIB) -I$(INST_LIB) -I$(PERL_ARCHLIB) -I$(PERL_LIB) $(TEST_FILE) test_ : test_dynamic test_static :: test_dynamic testdb_static :: testdb_dynamic # --- MakeMaker ppd section: # Creates a PPD (Perl Package Description) for a binary distribution. ppd: @$(PERL) -e "print qq{\n}. qq{\tRouter-LG-Cisco\n}. qq{\t\n}. qq{\t\n}. qq{\t\n}. qq{\t\t\n}. qq{\t\t\n}. qq{\t\t\n}. qq{\t\n}. qq{\n}" > Router-LG-Cisco.ppd # --- MakeMaker pm_to_blib section: pm_to_blib: $(TO_INST_PM) @$(PERL) "-I$(INST_ARCHLIB)" "-I$(INST_LIB)" \ "-I$(PERL_ARCHLIB)" "-I$(PERL_LIB)" -MExtUtils::Install \ -e "pm_to_blib({qw{$(PM_TO_BLIB)}},'$(INST_LIB)/auto')" @$(TOUCH) $@ # --- MakeMaker selfdocument section: # --- MakeMaker postamble section: # End. ) config :: $(INST_AUTODIR)/.exists @$(NOOP) $(INST_AUTODIR)/.exists :: /usr/local/lib/perl5/5.00503/sun4-solaris/CORE/perl.h @$(MKPATH) $(INST_AUTODIR) @$(EQUALIZE_TIMESTAMP) /usr/local/lib/perl5/5Router/LG/README010064400010200000062000000022640713140213000147270ustar00cjosephsysengr00000400000366Router::LG version 0.98 NAME Router::LG - Looking Glass DESCRIPTION The Router::LG module is designed to let network administrators give outsiders the ability to execute simple arbitrary commands on routers for the purposes of providing information that would normally have to be obtained by the network administrator directly. Users of this module should have a basic understanding of the operations of their routers. INSTALLATION 1. perl Makefile.PL 2. make 3. make test 4. make install DOCUMENTATION All modules included have POD documentation. Also, there are additional files in the distribution that should be examined. Routers.txt Information on data structures and creating additional modules for Routers::LG Security.txt Security concerns on using Router::LG. AUTHOR Chris Josephes SPECIAL THANKS Thanks to the following network engineers who assisted in the development of this software: Dan Boehlke, Dave Bergum, Rob Healey, Bradley Urberg Carlson, and Tom Barron. COPYRIGHT Copyright (c) 2000 Chris Josephes. All rights reserved. This program is free software; you may redistribute it and/or modify it under the same terms as Perl itself. Router/LG/Routers.txt010064400010200000062000000042460712645120000162630ustar00cjosephsysengr00000400000366Routers ======= This document is designed to provide information to hardware vendors or anyone for that matter on how to implement a driver module that can be used with the Router::LG module. For more information, check the source code for one of the modules that come with the Router::LG distribution. The Router data structure ------------------------- When the Router::LG::router() method is called, it expects to be passed an anonymous hash reference with the following structure: $router={ -hostname => "host", -class => "class", -method => "access_method", -args => { }, }; Key Explanation --- ----------- hostname The fully qualified domain name of the router class The Router::LG class to use for accessing this router method What remote access method/protocol used to communicate with the remote router. If omitted, the router class should specify a default method. args Arguements that may be required to communicate with the router. The Command data structure -------------------------- Public commands that a router can execute are defined with the following structure. $command={ -command => "command string", -cache => (1|0), }; Key Explanation --- ----------- cache Determines whether or not the command output can be cached to a local file. Note that if arguements are passed to the command, LG.pm cannot cache the output. label A descriptive label for the command, to assist in building front-end access tools command The actual command string sent to the router with substitution macros for user input. The Macros adhere to the following regex: [!%][ahi]+ The ! character means that user input must be inserted at this point. The % character means the input is optional. The characters following relate to the type of data that must be passed. "a" refers to AS number, "h" refers to hostname, and "i" refers to IP address. Although I haven't implemented it yet, I have decided to eliminate this kind of type-checking. It leads to too much input possibilities to check, and ideally, the command line interface of the router itself is best suited to determine whether or not input passed to it is valid. uter class The Router::LG class to use for accessing this router method What remote access method/protocol used to communicate with the remote router. If omitted, the router class should specify a default method. args Arguements that may be required to communicate with the router. The Command data structure --------------------Router/LG/Todo.txt010064400010200000062000000037330716042735400155400ustar00cjosephsysengr00000400000366Todo ==== Things todo in the near future. 1. Rethink router "driver" naming hierarchy. Originally Router::LG.pm was just LG.pm, but the CPAN guys didn't like the idea of a 2 letter top-level name hierarchy (can't say that I blame them). So I changed it to Router::LG at their suggestion. But now I'm thinking that maybe this can lead to bigger and better things down the road. What if other developers wanted to create modules to manage Router configurations, routing tables, etc, etc. Ideally, a hierarchy would look something like this Router::Driver::[Vendor] - Remote access routines Router::LG - Looking Glass Router::Config - Configuration data structure In some cases, where Router::* modules require more data than the "Driver" module contains, more hierarchies could be created under the module in question. Router::Driver::Cisco - Contains strict remote access methods Router::LG::Cisco - Contains a list of accepted "public" commands and uses "Router::Driver::Cisco" to access the router. I doubt that I could implement all of this myself, but it's an interesting proposal for a framework. It probably needs to pass the muster of the CPAN maintainers. 2. Rethink the command structure The defined command structure is pretty complex. It specifies types of data, yet the Router::LG module doesn't perform any type checking at all. I'm probably going to make this simpler, and depend on the router to remove tainted input. It shouldn't be too risky. (See "Routers"). 3. General code cleanup Some of the code is a little messy IMHO, and there are probably one or two perl conventions that I am not adhering to. This will be corrected in a future version. 4. Rethink information retrieval methodology The Looking Glass is necessary for traceroute and ping functions, but is it needed for information retrieval functions? If the same information is retrievable by SNMP, should SNMP be used instead of command line access? Just something to think about. Router/LG/Security.txt010064400010200000062000000063540712644643300164450ustar00cjosephsysengr00000400000366Security ======== This document serves to point out some security concerns implementors of the Router::LG module should be aware of. Overview -------- The whole purpose of the Router::LG class is to run commands on routers from a remote host. This in itself is a bad idea. There is no end to the amount of potential abuse that could occur from implementing a Looking Glass. Keep in mind that when access is opened up to a system, the system is proportionately less secure. If you are highly concerned about the security of your routers, you may not want to use these modules. If you want to provide tools for outsiders to examine basic information on your routers, you should be aware of the consequences of doing so and take steps to ensure the system can be as secure as possible. Also note that in some cases the ability to secure your routers may be dependent on the functionality of your router. Host Security ------------- If you are designing a web-based or CLI based tool for accessing a router, keep the following things in mind. 1. User input should be kept to a minumum. The end-user should never be allowed to specify options such as the router hostname, commands to execute, authentication information, or cache-file location. 2. Protect the program If you're implementing a CLI program, keep in mind that end users can read the actual perl script file. Make sure you don't reveal too much information within your perl code. 3. Usage logs Log usage of the program, and review it at regular intervals. Record all parameters that were passed by a user to the program. Network Security ---------------- 1. Network sniffing If you are accessing your router by using a non-encrypted protocol (RSH/Telnet), you run the risk of authentication information being sniffed. Your router vendor may have ways for you to increase the security of your router to minimize the risk. Consider the following options: a. Define a seperate protocol for use by Router::LG. If engineers always access routers with the "telnet" protocol, have Router::LG use the "rsh" protocol. b. Define authentication information specific to Router::LG. Create a user account/password set just for use by the Router::LG command. c. Limit command sets and incoming hosts If possible, create access lists to make sure that the authenticaiton information and access protocol used by Router::LG can only be sent from the IP address that the front end program is running on. Also, try to limit what commands Router::LG will be allowed to run. 2. Denial of Service Theoretically, a user could create a client to attack a web-based LG front end, or they could spawn multiple copies of a CLI based LG front end. DoS attacks aren't usually caught until it's too late, and it's kind of hard to catch it within the program that is running. Consider the following ideas to prevent DoS attacks: a. Strictly monitor the usage of the front-end program. If it isn't expected to be used often, log program runs to syslog. b. Limit incoming connections to the router. If possible, have the router limit the number of incoming connections the front-end can make. Technically, this could still result in a DoS attack, but it should decrease the impact of the activity on the router CPU.