Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Broken Net::Telnet::Netscreen module?

by spivey49 (Monk)
on Aug 12, 2008 at 20:52 UTC ( #703961=perlquestion: print w/replies, xml ) Need Help??

spivey49 has asked for the wisdom of the Perl Monks concerning the following question:

Solution

Turns out I didn't break the module. After much debugging I reverted back to the Net::Telnet module. Perlbotics provides a work around for the issues I was seeing with the Net::Telnet::Netscreen module below. Here's the working script in case someone finds it useful some day:

use strict; use warnings; use Net::Telnet; use Net::IP; use Getopt::Long; my $usage = "\nThis script will configure a netscreen firewall with a set of addre +sses and rules.\n" . "Rules will allow all traffic from a set of source IP addresses to + any destination on any port.\n\n" . "\nUsage: \n-h Host (firewall) to configure\n-u User \n-p Password +\n" . "-t Run a test run to only generate rules and addresses.\n\t-t wil +l not apply a configuration to the firewall\n" . "\tCan be used in conjunction with -set and -unset \n\tto generate + different command sets. Default is -set\n" . "-policyid Policy ID to start the set of rules at.\n\tDefault is 1 +50\n" . "-iprange Range of IPs to generate source addresses for.\n\tDefaul +t is 1.1.0.1 - 1.1.1.245\n" . "-from The zone traffic will be sourced from in the rules.\n\tDefa +ult is Untrust\n" . "-to The zone traffic will be destined to in the rules.\n\tDefault + is Trust\n" . "-zone The zone the addresses will be associated with.\n\tDefault +is Untrust\n" . "-set Apply the rules and addresses to the firewall\n-unset Remove + the rules from the firewall\n" . "-l Optional log file. Enter the full path to the log file.\n\tIf + the file exists it will be overwritten\n" . "-help or -? for this message.\n \nUsername, Password, and Host ar +e required.\n\n"; our ( $host, $uname, $pw, $set, $unset, $policyid, $iprange, $test, $vsys, $from, $to, $zone, $log, $help, $fw, $err ); GetOptions( "h=s" => \$host, "u=s" => \$uname, "p=s" => \$pw, "set" => \$set, "unset" => \$unset, "policyid=s" => \$policyid, "iprange=s" => \$iprange, "t" => \$test, "vsys=s" => \$vsys, "from=s" => \$from, "to=s" => \$to, "zone=s" => \$zone, "l=s" => \$log, "help|?:s" => \$help ); die $usage unless ( $uname and $pw and $host ) or $help; #Set defualts unless ($policyid) { $policyid = 150; } unless ($iprange) { $iprange = '1.1.0.1-1.1.1.245'; } unless ($from) { $from = "Untrust"; } unless ($to) { $to = "Trust"; } unless ($zone) { $zone = "Untrust"; } our $ip = new Net::IP($iprange) or die; my $prompt = '/[\w().-]*\(?([\w.-])?\)?\s*->\s*$|Done/'; if ($log) { open( LOG, "> $log" ) or die "Couldn't open file " . $log; + } if ($test) { &test; } elsif ($unset) { $fw = new Net::Telnet( host => $host ); unless ( $fw->login( $uname, $pw ) ) { print $fw->errmsg } &unset_config; } elsif ($set) { $fw = new Net::Telnet( host => $host ); unless ( $fw->login( $uname, $pw ) ) { print $fw->errmsg } &set_config; } if ($log) { close LOG or die "file not open" } sub test { my $count = 1; my $tstmsg = ''; $tstmsg = buildmsg( "#" x 65, "\n" ); $tstmsg = buildmsg( $tstmsg, "Will log into $host with username $uname and password $pw\n" +); $tstmsg = buildmsg( $tstmsg, "We will start at policy ID $policyid and IP range $iprange\n" + ); $tstmsg = buildmsg( $tstmsg, "#" x 65 ); $tstmsg = buildmsg( $tstmsg, "\n\n" ); print $tstmsg; if ($log) { print LOG $tstmsg } if ($unset) { do { $tstmsg = buildmsg( $ip->ip() . " :ip# $count\n" ); my $addrname = "AutoGenRule_" . $ip->ip(); my $rule = unset_rule( $addrname, $policyid ); $tstmsg = buildmsg( $tstmsg, "unset policy id $rule\n" ); my $addr = unset_addr($addrname); $tstmsg = buildmsg( $tstmsg, "unset address $addr\n" ); print $tstmsg; if ($log) { print LOG $tstmsg } ++$policyid; ++$count; } while ( ++$ip ); } else { do { $tstmsg = buildmsg( $ip->ip() . " :ip# $count\n" ); my $addrname = "AutoGenRule_" . $ip->ip(); my $addr = set_addr( $addrname, $ip->ip() ); $tstmsg = buildmsg( $tstmsg, "set address $addr\n" ); my $rule = set_rule( $addrname, $policyid ); $tstmsg = buildmsg( $tstmsg, "set policy id $rule\n" ); print $tstmsg; if ($log) { print LOG $tstmsg } ++$policyid; ++$count; } while ( ++$ip ); } $tstmsg = "Generated $count address and policy objects"; print $tstmsg; if ($log) { print LOG $tstmsg } } #end sub test sub unset_config() { if ( defined $fw ) { my $result; if ($vsys) { $result = cmd("enter vsys $vsys") } unless ($result) { print $err die } else { print "Entered Vsys $vsys\n" } do { my $addrname = "AutoGenRule_" . $ip->ip(); my $rule = unset_rule($policyid); my $addr = unset_addr( $addrname, $ip->ip() ); my $rulemsg = cmd($rule); my $addrmsg = cmd($addr); if ($rulemsg) { $rulemsg = "Removed policy $policyid with command\n\t$ +rule\n"; } else { print "Could not remove policy $policyid with command\n\t$rule\n\tError:$err +\n"; } if ($addrmsg) { $addrmsg = "Removed address $addrname with command\n\t +$addr\n"; } else { print "Could not remove address $addrname with command\n\t$addr\n\tError:$er +r\n"; } print $addrmsg, $rulemsg; if ($log) { print LOG $addrmsg, $rulemsg } ++$policyid; } while ( ++$ip ); } if ($vsys) { cmd("save conf"); cmd("exit"); } cmd("save conf"); $fw->close; } sub set_config() { if ( defined $fw ) { my $result; if ($vsys) { $result = cmd("enter vsys $vsys") } unless ($result) { print $err} else { print "Entered Vsys $vsys\n" } do { $err = undef; my $addrname = "AutoGenRule_" . $ip->ip(); my $rule = set_rule( $addrname, $policyid ); my $addr = set_addr( $addrname, $ip->ip() ); my $addrmsg = cmd($addr); my $rulemsg = cmd($rule); if ($addrmsg) { $addrmsg = "Added address $addrname with command\n\t$a +ddr\n"; } else { $addrmsg = "Could not add address $addrname with command\n\t$addr\n\tError:$err\n +"; } if ($rulemsg) { $rulemsg = "Added policy $policyid with command\n\t$ru +le\n"; } else { $rulemsg = "Could not add policy $policyid with command\n\t$rule\n\tError:$err\n" +; } print $addrmsg, $rulemsg; if ($log) { print LOG $addrmsg, $rulemsg } ++$policyid; } while ( ++$ip ); if ($vsys) { cmd("save conf"); cmd("exit"); } cmd("save conf"); $fw->close; } } sub set_addr { my $addrname = shift; my $ipaddr = shift; my $addr = "set address $zone $addrname $ipaddr\/32 Autocreate +d"; return $addr; } sub set_rule { my $addrname = shift; my $policyid = shift; my $rule = "set policy id $policyid from $from to $to $addrname any any per +m log"; return $rule; } sub unset_addr { my $addrname = shift; my $addr = "unset address $zone $addrname"; return $addr; } sub unset_rule { my $policyid = shift; my $rule = "unset policy id $policyid"; return $rule; } sub cmd { my $cmd = shift; my ( my $errmsg, my $line, my @lines ); unless ( $fw->eof ) { @lines = $fw->cmd($cmd); } foreach $line (@lines) { if ( $line =~ /\^-|(N|n)ot|(F|f)ail/ ) { $err = $line } } if ( $fw->errmsg ) { $err = $fw->$errmsg } if ($err) { return 0 } return 1; } sub buildmsg { my $msg = shift; my $append = shift; $msg = $msg . $append; return $msg; }

I have a script that adds address and policy objects to a Netscreen firewall. I found Net::Telnet::Netscreen that seemed a little more Netscreen friendly than the Net::Telnet module.

I'm not sure, but I think I might have broken my Net::Telnet::Netscreen module. The original module has a setValue method, but not an unsetValue method, so I added one. My script will send one command to the firewall, then exit. The -t option to the script still works fine and shows correct multiple commands the script will generate.

UPDATE: perlbotics suggested I update the question with the @ARGVs being passed to the script:

perl Rules.pl -h 10.99.59.253 -u netscreen -p netscreen -l c:\log.txt -iprange 1.1.0.1-1.1.0.2 -set

The firewall shows the script logging in, executing a command, saving the config, then exiting after one command

Here's the original setValue method:

#set a value in ns box sub setValue { my ($self,$setting, $value) = @_; return $self->error("No setting specified") unless $setting; return $self->error("No value specified") unless $value; my @results=$self->cmd("set ".$setting." ".$value); foreach my $result (@results) { if ($result =~ /\w+/) { return $self->error($result); } } return 1; }

I added this sub for the unsetValue method and reinstalled the module:

sub unsetValue { my ($self,$setting, $value) = @_; return $self->error("No setting specified") unless $setting; return $self->error("No value specified") unless $value; my @results=$self->cmd("unset ".$setting." ".$value); foreach my $result (@results) { if ($result =~ /\w+/) { return $self->error($result); } } return 1; }

Here's the script I'm using the module in:

use strict; use warnings; use Net::Telnet::Netscreen; use Net::IP; use Getopt::Long; my $usage = "\nThis script will configure a netscreen firewall with a set of addre +sses and rules.\n" . "Rules will allow all traffic from a set of source IP addresses to + any destination on any port.\n\n" . "\nUsage: \n-h Host (firewall) to configure\n-u User \n-p Password +\n" . "-t Run a test run to see the rules and addresses.\n\t-t will not +apply a configuration to the firewall\n" . "\tCan be used in conjunction with -set and -unset \n\tto generate + different command sets. Default is -set\n" . "-policyid Policy ID to start the set of rules at.\n\tDefault is 1 +50\n" . "-iprange Range of IPs to generate source addresses for.\n\tDefaul +t is 1.1.0.0 - 1.1.1.245\n" . "-from The zone traffic will be sourced from in the rules.\n\tDefa +ult is Untrust\n" . "-to The zone traffic will be destined to in the rules.\n\tDefault + is Trust\n" . "-zone The zone the addresses will be associated with.\n\tDefault +is Untrust\n" . "-set Apply the rules and addresses to the firewall\n-unset Remove + the rules from the firewall\n" . "-l Optional log file. Enter the full path to the log file.\n\tIf + the file exists it will be overwritten\n" . "-help or -? for this message.\n \nUsername, Password, and Host ar +e required.\n\n"; our ( $host, $uname, $pw, $set, $unset, $policyid, $iprange, $test, $vsys, $from, $to, $zone, $log, $help, $fw ); GetOptions( "h=s" => \$host, "u=s" => \$uname, "p=s" => \$pw, "set" => \$set, "unset" => \$unset, "policyid=s" => \$policyid, "iprange=s" => \$iprange, "t" => \$test, "vsys=s" => \$vsys, "from=s" => \$from, "to=s" => \$to, "zone=s" => \$zone, "l=s" => \$log, "help|?:s" => \$help ); die $usage unless ( $uname and $pw and $host ) or $help; unless ($policyid) { $policyid = 150; } unless ($iprange) { $iprange = '1.1.0.2 - 1.1.1.245'; } unless ($from) { $from = "Untrust"; } unless ($to) { $to = "Trust"; } unless ($zone) { $zone = "Untrust"; } our $ip = new Net::IP($iprange) or die; if ($log) { open( LOG, "> $log" ) or die "Couldn't open file " . $log; + } if ($test) { &test; } elsif ($unset) { $fw = new Net::Telnet::Netscreen( host => $host ); $fw->login( $uname, $pw ) or die $fw->error; &unset_config; } elsif ($set) { $fw = new Net::Telnet::Netscreen( host => $host ); $fw->login( $uname, $pw ) or die $fw->error; &set_config; } close LOG or die "file not open"; sub test { my $count = 1; print "#" x 65, "\n"; print "Will log into $host with username $uname and password $pw\n +"; print "We will start at policy ID $policyid and IP range $iprange\ +n"; print "The following addresses and rules will be generated:\n"; print "#" x 65, "\n\n"; if ($unset) { do { print $ip->ip() . " :ip# $count\n"; my $addrname = "AutoGenRule_" . $ip->ip(); my $rule = unset_rule( $addrname, $policyid ); print "unset policy id $rule\n"; my $addr = unset_addr($addrname); print "unset address $addr\n"; ++$policyid; ++$count; } while ( ++$ip ); } else { do { print $ip->ip() . " :ip# $count\n"; my $addrname = "AutoGenRule_" . $ip->ip(); my $addr = set_addr( $addrname, $ip->ip() ); print "set address $addr\n"; my $rule = set_rule( $addrname, $policyid ); print "set policy id $rule\n"; ++$policyid; ++$count; } while ( ++$ip ); } } sub unset_config() { if ( defined $fw ) { if ($vsys) { $fw->enter_vsys($vsys) } do { my $addrname = "AutoGenRule_" . $ip->ip(); my $rule = unset_rule( $addrname, $policyid ); my $addr = unset_addr( $addrname, $ip->ip() ); my $rulemsg = $fw->unsetValue( "policy id", $rule ); my $addrmsg = $fw->unsetValue( "address", $addr ); if ($rulemsg) { print "Removed $rule\n"; } else { print "Could not remove $rule\n" . $fw->error . "\n +"; } if ($addrmsg) { print "Removed $addr\n"; } else { print "Could not remove $addr\n" . $fw->error . "\n +"; } if ( $rulemsg and $log ) { print LOG "Removed $rule"; } else { print LOG "Could not remove $rule\n" . $fw->error . + "\n"; } if ( $addrmsg and $log ) { print LOG "Removed $addr"; } else { print LOG "Could not remove $addr\n" . $fw->error . + "\n"; } } while ( ++$ip ); } } sub set_config() { if ( defined $fw ) { if ($vsys) { $fw->enter_vsys($vsys) } do { my $addrname = "AutoGenRule_" . $ip->ip(); my $rule = set_rule( $addrname, $policyid ); my $addr = set_addr( $addrname, $ip->ip() ); my $addrmsg = $fw->setValue( "address", $addr ); my $rulemsg = $fw->setValue( "policy id", $rule ); if ($rulemsg) { print "Added $rule"; } else { print "Could not add $rule\n" . $fw->error + . "\n"; } if ($addrmsg) { print "Added $addr"; } else { print "Could not add $addr\n" . $fw->error + . "\n"; } if ( $rulemsg and $log ) { print LOG "Added $rule\n"; } else { print LOG "Could not add $rule\n" . $fw->error . "\ +n"; } if ( $addrmsg and $log ) { print LOG "Added $addr\n"; } else { print LOG "Could not add $addr\n" . $fw->error . "\ +n"; } } while ( ++$ip ); } } sub set_addr() { my $addrname = shift; my $ipaddr = shift; my $addr = "$zone $addrname $ipaddr\/32 \"Created with perl for te +sting\""; return $addr; } sub set_rule() { my $addrname = shift; my $policyid = shift; my $rule = "$policyid from $from to $to $addrname any any perm + log"; return $rule; } sub unset_addr() { my $addrname = shift; my $addr = "$zone $addrname"; return $addr; } sub unset_rule() { my $ipaddr = shift; my $policyid = shift; my $rule = $policyid; return $rule; }

The subs causing me grief are the set_config and unset_config subs. The unset_addr and unset_rule subs are left over from using Net::Telnet and aren't really doing much. I'll be taking those out later.

Replies are listed 'Best First'.
Re: Broken Net::Telnet::Netscreen module?
by jethro (Monsignor) on Aug 13, 2008 at 00:50 UTC

    My first idea was that you had overridden an internal sub unsetValue, but I checked that and there is none

    I can't think of any other reason why your addition should break anything. Maybe someone else can??

    So my guess is that this either has nothing to do with the malfunction or you changed code somewhere else too (maybe by mistake). Did you check that reverting the module to its old state also changes its behaviour to normal?

    But I think the best source of information for you would be to use the perl debugger with trace or single step to find out why it stops prematurely.

      I tried reverting the module with the same results, so it appears the problem is in the script.

      Here's the debug output:

      I'm not entirely sure how to interpret this. Any thoughts?

        This means the error function gets called in your method unsetValue. Since the parameters are definitely not empty the call is probably because of this line

        if ($result =~ /\w+/) { return $self->error($result); }

        this line should be on line 150 of your changed Netscreen.pm. I don't know what is in $result, but normally you should get some error message while running the script and that return value is probably what the telnet session answered when the unset command was issued to the netscreen machine. Noticing (and reporting) that error message would have made things much easier

        If you don't see this error message, you might put something like  print STDERR "<<$result>>\n"; between line 149 and 150 into Netscreen.pm.

        The probable cause of that error is that the unset command on the netscreen machine doesn't need/want/allow a parameter $value, because you are UNSETTING and not setting a value. So you might try the following line in your unsetValue method

        my @results=$self->cmd("unset ".$setting);
Re: Broken Net::Telnet::Netscreen module?
by Perlbotics (Chancellor) on Aug 17, 2008 at 14:43 UTC

    Probably good news, spivey49. Your program starts to die when Net::Telnet::Netscreen restores the settings of Net::Telnet before calling Telnet::error() in &scrolling_cmd. By default, Net::Telnet dies on error. So this is not really a bug in Net::Telnet::Netscreen, just behaviour inherited from Net::Telnet. When something goes wrong your program dies. You can see that by setting $SIG{__DIE__}.

    You may continue with one of the two (there are more, see Net::Telnet) alternatives:

    ... # w/o ALT1,2 - try: $SIG{__DIE__} = sub { warn "\nDIIIII\n", caller }; $fw = new Net::Telnet::Netscreen( host => $host ); # ALT1: Ignore (bad idea, but quick debugging fix): # $fw->errmode("return"); # ALT2: Analyse problem yourself / decide to abort or to continue: # $fw->errmode( sub { warn "ERRHANDLER: @_\n"; } ); ...

    Since I don't own a Netscreen FW, I simulated it manually with netcat. Here is what your program does (it misses a 'save'?):

    login:
    netscreen
    password:
    netscreen
    set address Untrust AutoGenRule_1.1.0.1 1.1.0.1/32 "Created with perl for testing"
    set policy id 150 from Untrust to Trust AutoGenRule_1.1.0.1 any any perm log
    set address Untrust AutoGenRule_1.1.0.2 1.1.0.2/32 "Created with perl for testing"
    set policy id 150 from Untrust to Trust AutoGenRule_1.1.0.2 any any perm log
    
    Being not a well trained Netscreen FW, I didn't respond to the commands. Consequently, a timeout occurred, which was ignored due to reconfiguring the error-behaviour to "return". You might experience other errors, but your program won't die in the middle of somewhere. One small step forward...

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://703961]
Approved by Old_Gray_Bear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (5)
As of 2019-12-08 16:04 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?