File Coverage

blib/lib/Cisco/SNMP/Config.pm
Criterion Covered Total %
statement 18 191 9.4
branch 0 104 0.0
condition 0 15 0.0
subroutine 6 10 60.0
pod 3 3 100.0
total 27 323 8.3


line stmt bran cond sub pod time code
1             package Cisco::SNMP::Config;
2              
3             ##################################################
4             # AUTHOR = Michael Vincent
5             # www.VinsWorld.com
6             ##################################################
7              
8 1     1   45585 use strict;
  1         10  
  1         26  
9 1     1   5 use warnings;
  1         1  
  1         25  
10              
11 1     1   562 use Net::SNMP qw(:asn1);
  1         59470  
  1         223  
12 1     1   379 use Cisco::SNMP;
  1         3  
  1         54  
13              
14             our $VERSION = $Cisco::SNMP::VERSION;
15              
16             our @ISA = qw(Cisco::SNMP);
17              
18 1     1   7 use Sys::Hostname;
  1         1  
  1         41  
19 1     1   5 use Socket qw(AF_INET);
  1         1  
  1         1620  
20              
21             my $AF_INET6 = eval { Socket::AF_INET6() };
22              
23             my %PROTO = (
24             tftp => 1,
25             ftp => 2,
26             rcp => 3,
27             scp => 4,
28             sftp => 5
29             );
30              
31             ##################################################
32             # Start Public Module
33             ##################################################
34              
35             sub config_copy {
36 0     0 1   my $self = shift;
37 0   0       my $class = ref($self) || $self;
38              
39 0           my $session = $self->{_SESSION_};
40              
41 0           my %params = (
42             op => 'wr',
43             catos => 0,
44             timeout => 10,
45             source => 4,
46             dest => 3,
47             protocol => 'tftp',
48             username => 'cisco',
49             password => 'cisco'
50             );
51              
52 0           my %args;
53 0 0         if ( @_ == 1 ) {
54 0           $Cisco::SNMP::LASTERROR = "Insufficient number of args";
55 0           return undef;
56             } else {
57 0           %args = @_;
58 0           for ( keys(%args) ) {
59 0 0 0       if ( (/^-?(?:tftp)?server$/i) || (/^-?tftp$/) ) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
60 0           $params{server} = $args{$_};
61             } elsif (/^-?catos$/i) {
62 0 0         if ( $args{$_} == 1 ) {
63 0           $params{catos} = 1;
64             }
65             } elsif (/^-?user(?:name)?$/i) {
66 0           $params{username} = $args{$_};
67             } elsif (/^-?pass(?:word)?$/i) {
68 0           $params{password} = $args{$_};
69             } elsif (/^-?timeout$/i) {
70 0           $params{timeout} = $args{$_};
71             } elsif (/^-?proto(?:col)?$/i) {
72 0 0         if ( exists( $PROTO{lc( $args{$_} )} ) ) {
73 0           $params{protocol} = lc( $args{$_} );
74             } else {
75 0           $Cisco::SNMP::LASTERROR = "Invalid protocol `$args{$_}'";
76 0           return undef;
77             }
78             } elsif (/^-?family$/i) {
79 0 0         if ( $args{$_}
80 0           =~ /^(?:(?:(:?ip)?v?(?:4|6))|${\AF_INET}|$AF_INET6)$/ ) {
81 0 0         if ( $args{$_} =~ /^(?:(?:(:?ip)?v?4)|${\AF_INET})$/ ) {
  0            
82 0           $params{family} = AF_INET;
83             } else {
84 0           $params{family} = $AF_INET6;
85             }
86             } else {
87 0           $Cisco::SNMP::LASTERROR = "Invalid family `$args{$_}'";
88 0           return undef;
89             }
90             } elsif (/^-?source$/i) {
91 0 0         if ( $args{$_} =~ /^run(?:ning)?(?:-config)?$/i ) {
    0          
92 0           $params{source} = 4;
93             } elsif ( $args{$_} =~ /^start(?:up)?(?:-config)?$/i ) {
94 0           $params{source} = 3;
95             } else {
96 0           $params{source} = 1;
97 0           $params{op} = 'put';
98 0           $params{file} = $args{$_};
99             }
100             } elsif (/^-?dest(?:ination)?$/i) {
101 0 0         if ( $args{$_} =~ /^run(?:ning)?(?:-config)?$/i ) {
    0          
102 0           $params{dest} = 4;
103             } elsif ( $args{$_} =~ /^start(?:up)?(?:-config)?$/i ) {
104 0           $params{dest} = 3;
105             } else {
106 0           $params{dest} = 1;
107 0           $params{op} = 'get';
108 0           $params{file} = $args{$_};
109             }
110             }
111             }
112             }
113 0           my $cc;
114 0           $cc->{_params_} = \%params;
115              
116 0 0         if ( $params{source} == $params{dest} ) {
117 0           $Cisco::SNMP::LASTERROR = "Source and destination cannot be same";
118 0           return undef;
119             }
120              
121             # server must be defined if put/get
122 0 0 0       if ( ( $params{op} ne 'wr' ) and not defined $params{server} ) {
123 0           $params{server} = hostname;
124             }
125              
126             # inherit from new()
127 0 0         if ( not defined $params{family} ) {
128 0           $params{family} = $self->{family};
129             }
130              
131 0 0 0       if ( $params{catos} and $params{protocol} ne 'tftp' ) {
132 0           $Cisco::SNMP::LASTERROR = "CatOS only supports tftp";
133 0           return undef;
134             }
135              
136             # resolve server our way
137 0 0         if ( defined $params{server} ) {
138 0 0         if (defined(
139             my $ret
140             = Cisco::SNMP::_resolv( $params{server}, $params{family} )
141             )
142             ) {
143 0           $params{server} = $ret->{addr};
144 0           $params{family} = $ret->{family};
145             } else {
146 0           return undef;
147             }
148 0 0 0       if ( $params{catos} and $params{family} == $AF_INET6 ) {
149 0           $Cisco::SNMP::LASTERROR = "CatOS does not support IPv6";
150 0           return undef;
151             }
152             }
153              
154 0           my $response;
155 0           my $instance = int( rand(1024) + 1024 );
156 0           my %ioserr = (
157             1 => "Unknown",
158             2 => "Bad file name",
159             3 => "Timeout",
160             4 => "No memory",
161             5 => "No config",
162             6 => "Unsupported protocol",
163             7 => "Config apply fail",
164             8 => "System not ready",
165             9 => "Request abort"
166             );
167              
168             # wr mem
169 0 0         if ( $params{op} eq 'wr' ) {
170 0 0         if ( $params{catos} ) {
171 0           $Cisco::SNMP::LASTERROR
172             = "CatOS does not support `copy run start'";
173 0           return undef;
174             }
175              
176             # ccCopyEntryRowStatus (5 = createAndWait, 6 = destroy)
177             $response
178 0           = $session->set_request(
179             '1.3.6.1.4.1.9.9.96.1.1.1.1.14.' . $instance,
180             INTEGER, 6 );
181              
182 0 0         if ( not defined $response ) {
183              
184             # copy run start NOT SUPPORTED - trying old way
185 0           $response
186             = $session->set_request( '1.3.6.1.4.1.9.2.1.54.0', INTEGER, 1 );
187 0 0         if ( defined $response ) {
188 0           return bless $cc, $class;
189             } else {
190 0           $Cisco::SNMP::LASTERROR
191             = "`copy run start' FAILED (new and old)";
192 0           return undef;
193             }
194             }
195              
196             # ccCopySourceFileType (1 = networkFile, 3 = startupConfig, 4 = runningConfig)
197             $response
198             = $session->set_request(
199             '1.3.6.1.4.1.9.9.96.1.1.1.1.3.' . $instance,
200 0           INTEGER, $params{source} );
201              
202             # ccCopyDestFileType (1 = networkFile, 3 = startupConfig, 4 = runningConfig)
203             $response
204             = $session->set_request(
205             '1.3.6.1.4.1.9.9.96.1.1.1.1.4.' . $instance,
206             INTEGER, $params{dest} )
207              
208             # TFTP PUT/GET (to/from device)
209 0           } else {
210 0           $response = _config_copy( \%params, $session, $instance );
211 0 0         if ( $response == 0 ) {
    0          
212 0           return bless $cc, $class;
213             } elsif ( $response == -1 ) {
214 0           return undef;
215             }
216              
217             # $response == 1, continue ...
218             }
219              
220             # ccCopyEntryRowStatus (4 = createAndGo, 6 = destroy)
221 0           $response
222             = $session->set_request( '1.3.6.1.4.1.9.9.96.1.1.1.1.14.' . $instance,
223             INTEGER, 1 );
224              
225             # Check status, wait done
226 0           $response
227             = $session->get_request( '1.3.6.1.4.1.9.9.96.1.1.1.1.10.' . $instance );
228 0 0         if ( not defined $response ) {
229 0           $Cisco::SNMP::LASTERROR
230             = "$params{protocol} NOT SUPPORTED (after setup)";
231 0           return undef;
232             }
233              
234             # loop and check response - error if timeout
235 0           my $loop = 0;
236 0           while ( $response->{'1.3.6.1.4.1.9.9.96.1.1.1.1.10.' . $instance} <= 2 ) {
237 0           $response = $session->get_request(
238             '1.3.6.1.4.1.9.9.96.1.1.1.1.10.' . $instance );
239 0 0         if ( not defined $response ) {
240 0           $Cisco::SNMP::LASTERROR
241             = "IOS $params{protocol} `$params{op}' FAILED - cannot verify completion";
242 0           return undef;
243             }
244 0 0         if ( $loop++ == $params{timeout} ) {
245 0           $Cisco::SNMP::LASTERROR
246             = "IOS $params{protocol} `$params{op}' FAILED - timeout during completion verification";
247 0           return undef;
248             }
249 0           sleep 1;
250             }
251              
252             # Success
253 0 0         if ( $response->{'1.3.6.1.4.1.9.9.96.1.1.1.1.10.' . $instance} == 3 ) {
    0          
254 0           $response = $session->get_request(
255             '1.3.6.1.4.1.9.9.96.1.1.1.1.11.' . $instance );
256             $cc->{StartTime}
257 0           = $response->{'1.3.6.1.4.1.9.9.96.1.1.1.1.11.' . $instance};
258 0           $response = $session->get_request(
259             '1.3.6.1.4.1.9.9.96.1.1.1.1.12.' . $instance );
260             $cc->{EndTime}
261 0           = $response->{'1.3.6.1.4.1.9.9.96.1.1.1.1.12.' . $instance};
262 0           $session->set_request( '1.3.6.1.4.1.9.9.96.1.1.1.1.14.' . $instance,
263             INTEGER, 6 );
264 0           return bless $cc, $class
265              
266             # Error
267             } elsif ( $response->{'1.3.6.1.4.1.9.9.96.1.1.1.1.10.' . $instance} == 4 )
268             {
269 0           $response = $session->get_request(
270             '1.3.6.1.4.1.9.9.96.1.1.1.1.13.' . $instance );
271 0           $session->set_request( '1.3.6.1.4.1.9.9.96.1.1.1.1.14.' . $instance,
272             INTEGER, 6 );
273             $Cisco::SNMP::LASTERROR
274             = "IOS $params{protocol} `$params{op}' FAILED - "
275 0           . $ioserr{$response->{'1.3.6.1.4.1.9.9.96.1.1.1.1.13.' . $instance}
276             };
277 0           return undef;
278             } else {
279 0           $Cisco::SNMP::LASTERROR = "Cannot determine success or failure";
280 0           return undef;
281             }
282             }
283              
284             sub ccStartTime {
285 0     0 1   my $self = shift;
286 0           return $self->{StartTime};
287             }
288              
289             sub ccEndTime {
290 0     0 1   my $self = shift;
291 0           return $self->{EndTime};
292             }
293              
294             ##################################################
295             # End Public Module
296             ##################################################
297              
298             ##################################################
299             # Start Private subs
300             ##################################################
301              
302             # Return:
303             # -1 = error
304             # 0 = DONE
305             # 1 = continue
306             sub _config_copy {
307              
308 0     0     my ( $params, $session, $instance ) = @_;
309              
310 0           my $response;
311 0           my %caterr = (
312             1 => "In Progress",
313             2 => "Success",
314             3 => "No Response",
315             4 => "Too Many Retries",
316             5 => "No Buffers",
317             6 => "No Processes",
318             7 => "Bad Checksum",
319             8 => "Bad Length",
320             9 => "Bad Flash",
321             10 => "Server Error",
322             11 => "User Cancelled",
323             12 => "Wrong Code",
324             13 => "File Not Found",
325             14 => "Invalid TFTP Host",
326             15 => "Invalid TFTP Module",
327             16 => "Access Violation",
328             17 => "Unknown Status",
329             18 => "Invalid Storage Device",
330             19 => "Insufficient Space On Storage Device",
331             20 => "Insufficient Dram Size",
332             21 => "Incompatible Image"
333             );
334              
335 0 0         if ( $params->{catos} ) {
336             $response
337             = $session->set_request( '1.3.6.1.4.1.9.5.1.5.1.0', OCTET_STRING,
338 0           $params->{server} );
339             $response
340             = $session->set_request( '1.3.6.1.4.1.9.5.1.5.2.0', OCTET_STRING,
341 0           $params->{file} );
342 0           $response
343             = $session->set_request( '1.3.6.1.4.1.9.5.1.5.3.0', INTEGER, 1 );
344 0 0         if ( $params->{op} eq 'put' ) {
345 0           $response
346             = $session->set_request( '1.3.6.1.4.1.9.5.1.5.4.0', INTEGER,
347             2 );
348             } else {
349 0           $response
350             = $session->set_request( '1.3.6.1.4.1.9.5.1.5.4.0', INTEGER,
351             3 );
352             }
353              
354             # loop and check response - error if timeout
355 0 0         if (defined(
356             $response = $session->get_request('1.3.6.1.4.1.9.5.1.5.5.0')
357             )
358             ) {
359 0           my $loop = 0;
360 0           while ( $response->{'1.3.6.1.4.1.9.5.1.5.5.0'} == 1 ) {
361 0           $response = $session->get_request('1.3.6.1.4.1.9.5.1.5.5.0');
362 0 0         if ( $loop++ == $params->{timeout} ) {
363 0           $Cisco::SNMP::LASTERROR
364             = "CatOS TFTP `$params->{op}' FAILED - timeout during completion verification";
365 0           return -1;
366             }
367 0           sleep 1;
368             }
369             } else {
370 0           $Cisco::SNMP::LASTERROR
371             = "CatOS TFTP `$params->{op}' FAILED - can't get initial response";
372 0           return -1;
373             }
374              
375 0 0         if ( $response->{'1.3.6.1.4.1.9.5.1.5.5.0'} == 2 ) {
376 0           return 0;
377             } else {
378             $Cisco::SNMP::LASTERROR = "CatOS TFTP `$params->{op}' FAILED - "
379 0           . $caterr{$response->{'1.3.6.1.4.1.9.5.1.5.5.0'}};
380 0           return -1;
381             }
382              
383             # IOS
384             } else {
385              
386             # ccCopyEntryRowStatus (5 = createAndWait, 6 = destroy)
387 0           $response
388             = $session->set_request(
389             '1.3.6.1.4.1.9.9.96.1.1.1.1.14.' . $instance,
390             INTEGER, 6 );
391 0           $response
392             = $session->set_request(
393             '1.3.6.1.4.1.9.9.96.1.1.1.1.14.' . $instance,
394             INTEGER, 5 );
395              
396             # ccCopyProtocol
397             $response
398             = $session->set_request(
399             '1.3.6.1.4.1.9.9.96.1.1.1.1.2.' . $instance,
400 0           INTEGER, $PROTO{$params->{protocol}} );
401              
402 0 0         if ( not defined $response ) {
403 0           $Cisco::SNMP::LASTERROR
404             = "IOS TFTP `$params->{op}' NOT SUPPORTED - trying old way";
405 0 0         if ( $params->{protocol} ne 'tftp' ) {
406 0           $Cisco::SNMP::LASTERROR
407             = "Old way does not support `$params->{protocol}'";
408 0           return -1;
409             }
410 0 0         if ( $params->{family} == $AF_INET6 ) {
411 0           $Cisco::SNMP::LASTERROR
412             = "IOS TFTP `$params->{op}' old way does not support IPv6";
413 0           return -1;
414             }
415 0 0         if ( $params->{op} eq 'put' ) {
416             $response
417             = $session->set_request(
418             '1.3.6.1.4.1.9.2.1.50.' . $params->{server},
419 0           OCTET_STRING, $params->{file} );
420             } else {
421             $response
422             = $session->set_request(
423             '1.3.6.1.4.1.9.2.1.55.' . $params->{server},
424 0           OCTET_STRING, $params->{file} );
425             }
426 0 0         if ( defined $response ) {
427 0           return 0;
428             } else {
429 0           $Cisco::SNMP::LASTERROR
430             = "IOS TFTP `$params->{op}' FAILED (new and old)";
431 0           return -1;
432             }
433             }
434              
435 0 0         if ( $params->{protocol} ne 'tftp' ) {
436             $response
437             = $session->set_request(
438             '1.3.6.1.4.1.9.9.96.1.1.1.1.7.' . $instance,
439 0           OCTET_STRING, $params->{username} );
440 0 0         if ( $params->{protocol} ne 'rcp' ) {
441             $response
442             = $session->set_request(
443             '1.3.6.1.4.1.9.9.96.1.1.1.1.8.' . $instance,
444 0           OCTET_STRING, $params->{password} );
445             }
446             }
447              
448             # ccCopySourceFileType [.3] (1 = networkFile, 3 = startupConfig, 4 = runningConfig)
449             # ccCopyDestFileType [.4] (1 = networkFile, 3 = startupConfig, 4 = runningConfig)
450 0 0         if ( $params->{op} eq 'put' ) {
451 0           $response
452             = $session->set_request(
453             '1.3.6.1.4.1.9.9.96.1.1.1.1.3.' . $instance,
454             INTEGER, 1 );
455             $response
456             = $session->set_request(
457             '1.3.6.1.4.1.9.9.96.1.1.1.1.4.' . $instance,
458 0           INTEGER, $params->{dest} );
459             } else {
460             $response
461             = $session->set_request(
462             '1.3.6.1.4.1.9.9.96.1.1.1.1.3.' . $instance,
463 0           INTEGER, $params->{source} );
464 0           $response
465             = $session->set_request(
466             '1.3.6.1.4.1.9.9.96.1.1.1.1.4.' . $instance,
467             INTEGER, 1 );
468             }
469              
470             # New way
471             # ccCopyServerAddressType (1 = IPv4, 2 = IPv6)
472             $response
473             = $session->set_request(
474             '1.3.6.1.4.1.9.9.96.1.1.1.1.15.' . $instance,
475 0 0         INTEGER, ( $params->{family} == AF_INET ) ? 1 : 2 );
476              
477 0 0         if ( defined $response ) {
478              
479             # ccCopyServerAddressRev1
480             $response
481             = $session->set_request(
482             '1.3.6.1.4.1.9.9.96.1.1.1.1.16.' . $instance,
483 0           OCTET_STRING, $params->{server} );
484             } else {
485              
486             # Deprecated
487             # ccCopyServerAddress
488 0 0         if ( $params->{family} == $AF_INET6 ) {
489 0           $Cisco::SNMP::LASTERROR
490             = "ccCopyServerAddressRev1 not supported (requried for IPv6)";
491 0           return -1;
492             }
493             $response
494             = $session->set_request(
495             '1.3.6.1.4.1.9.9.96.1.1.1.1.5.' . $instance,
496 0           IPADDRESS, $params->{server} );
497             }
498              
499             # ccCopyFileName
500             $response
501             = $session->set_request(
502             '1.3.6.1.4.1.9.9.96.1.1.1.1.6.' . $instance,
503 0           OCTET_STRING, $params->{file} );
504             }
505 0           return 1;
506             }
507              
508             ##################################################
509             # End Private subs
510             ##################################################
511              
512             1;
513              
514             __END__