File Coverage

blib/lib/Cisco/SNMP/Config.pm
Criterion Covered Total %
statement 18 189 9.5
branch 0 102 0.0
condition 0 15 0.0
subroutine 6 10 60.0
pod 3 3 100.0
total 27 319 8.4


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   70513 use strict;
  1         3  
  1         31  
9 1     1   6 use warnings;
  1         2  
  1         32  
10              
11 1     1   851 use Net::SNMP qw(:asn1);
  1         109215  
  1         358  
12 1     1   638 use Cisco::SNMP;
  1         3  
  1         80  
13              
14             our $VERSION = $Cisco::SNMP::VERSION;
15              
16             our @ISA = qw(Cisco::SNMP);
17              
18 1     1   10 use Sys::Hostname;
  1         3  
  1         65  
19 1     1   9 use Socket qw(AF_INET);
  1         3  
  1         2472  
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             return undef
56 0           } 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             return undef
77 0           }
78             } elsif (/^-?family$/i) {
79 0 0         if ($args{$_} =~ /^(?:(?:(:?ip)?v?(?:4|6))|${\AF_INET}|$AF_INET6)$/) {
  0            
80 0 0         if ($args{$_} =~ /^(?:(?:(:?ip)?v?4)|${\AF_INET})$/) {
  0            
81 0           $params{family} = AF_INET
82             } else {
83 0           $params{family} = $AF_INET6
84             }
85             } else {
86 0           $Cisco::SNMP::LASTERROR = "Invalid family `$args{$_}'";
87             return undef
88 0           }
89             } elsif (/^-?source$/i) {
90 0 0         if ($args{$_} =~ /^run(?:ning)?(?:-config)?$/i) {
    0          
91 0           $params{source} = 4
92             } elsif ($args{$_} =~ /^start(?:up)?(?:-config)?$/i) {
93 0           $params{source} = 3
94             } else {
95 0           $params{source} = 1;
96 0           $params{op} = 'put';
97 0           $params{file} = $args{$_}
98             }
99             } elsif (/^-?dest(?:ination)?$/i) {
100 0 0         if ($args{$_} =~ /^run(?:ning)?(?:-config)?$/i) {
    0          
101 0           $params{dest} = 4
102             } elsif ($args{$_} =~ /^start(?:up)?(?:-config)?$/i) {
103 0           $params{dest} = 3
104             } else {
105 0           $params{dest} = 1;
106 0           $params{op} = 'get';
107 0           $params{file} = $args{$_}
108             }
109             }
110             }
111             }
112 0           my $cc;
113 0           $cc->{_params_} = \%params;
114              
115 0 0         if ($params{source} == $params{dest}) {
116 0           $Cisco::SNMP::LASTERROR = "Source and destination cannot be same";
117             return undef
118 0           }
119              
120             # server must be defined if put/get
121 0 0 0       if (($params{op} ne 'wr') && !defined $params{server}) {
122 0           $params{server} = hostname
123             }
124              
125             # inherit from new()
126 0 0         if (!defined $params{family}) {
127             $params{family} = $self->{family}
128 0           }
129              
130 0 0 0       if ($params{catos} && $params{protocol} != 'tftp') {
131 0           $Cisco::SNMP::LASTERROR = "CatOS only supports tftp";
132             return undef
133 0           }
134              
135             # resolve server our way
136 0 0         if (defined $params{server}) {
137 0 0         if (defined(my $ret = Cisco::SNMP::_resolv($params{server}, $params{family}))) {
138 0           $params{server} = $ret->{addr};
139             $params{family} = $ret->{family}
140 0           } else {
141             return undef
142 0           }
143 0 0 0       if ($params{catos} && ($params{family} == $AF_INET6)) {
144 0           $Cisco::SNMP::LASTERROR = "CatOS does not support IPv6";
145             return undef
146 0           }
147             }
148              
149 0           my $response;
150 0           my $instance = int(rand(1024)+1024);
151 0           my %ioserr = (
152             1 => "Unknown",
153             2 => "Bad file name",
154             3 => "Timeout",
155             4 => "No memory",
156             5 => "No config",
157             6 => "Unsupported protocol",
158             7 => "Config apply fail",
159             8 => "System not ready",
160             9 => "Request abort"
161             );
162              
163             # wr mem
164 0 0         if ($params{op} eq 'wr') {
165 0 0         if ($params{catos}) {
166 0           $Cisco::SNMP::LASTERROR = "CatOS does not support `copy run start'";
167             return undef
168 0           }
169             # ccCopyEntryRowStatus (5 = createAndWait, 6 = destroy)
170 0           $response = $session->set_request('1.3.6.1.4.1.9.9.96.1.1.1.1.14.' . $instance, INTEGER, 6);
171              
172 0 0         if (!defined $response) {
173             # copy run start NOT SUPPORTED - trying old way
174 0           $response = $session->set_request('1.3.6.1.4.1.9.2.1.54.0', INTEGER, 1);
175 0 0         if (defined $response) {
176 0           return bless $cc, $class
177             } else {
178 0           $Cisco::SNMP::LASTERROR = "`copy run start' FAILED (new and old)";
179             return undef
180 0           }
181             }
182              
183             # ccCopySourceFileType (1 = networkFile, 3 = startupConfig, 4 = runningConfig)
184 0           $response = $session->set_request('1.3.6.1.4.1.9.9.96.1.1.1.1.3.' . $instance, INTEGER, $params{source});
185             # ccCopyDestFileType (1 = networkFile, 3 = startupConfig, 4 = runningConfig)
186             $response = $session->set_request('1.3.6.1.4.1.9.9.96.1.1.1.1.4.' . $instance, INTEGER, $params{dest})
187              
188             # TFTP PUT/GET (to/from device)
189 0           } else {
190 0           $response = _config_copy(\%params, $session, $instance);
191 0 0         if ($response == 0) {
    0          
192 0           return bless $cc, $class
193             } elsif ($response == -1) {
194             return undef
195 0           }
196             # $response == 1, continue ...
197             }
198              
199             # ccCopyEntryRowStatus (4 = createAndGo, 6 = destroy)
200 0           $response = $session->set_request('1.3.6.1.4.1.9.9.96.1.1.1.1.14.' . $instance, INTEGER, 1);
201              
202             # Check status, wait done
203 0           $response = $session->get_request('1.3.6.1.4.1.9.9.96.1.1.1.1.10.' . $instance);
204 0 0         if (!defined $response) {
205 0           $Cisco::SNMP::LASTERROR = "$params{protocol} NOT SUPPORTED (after setup)";
206             return undef
207 0           }
208              
209             # loop and check response - error if timeout
210 0           my $loop = 0;
211 0           while ($response->{'1.3.6.1.4.1.9.9.96.1.1.1.1.10.' . $instance} <= 2) {
212 0           $response = $session->get_request('1.3.6.1.4.1.9.9.96.1.1.1.1.10.' . $instance);
213 0 0         if (!defined $response) {
214 0           $Cisco::SNMP::LASTERROR = "IOS $params{protocol} `$params{op}' FAILED - cannot verify completion";
215             return undef
216 0           }
217 0 0         if ($loop++ == $params{timeout}) {
218 0           $Cisco::SNMP::LASTERROR = "IOS $params{protocol} `$params{op}' FAILED - timeout during completion verification";
219             return undef
220 0           }
221 0           sleep 1
222             }
223              
224             # Success
225 0 0         if ($response->{'1.3.6.1.4.1.9.9.96.1.1.1.1.10.' . $instance} == 3) {
    0          
226 0           $response = $session->get_request('1.3.6.1.4.1.9.9.96.1.1.1.1.11.' . $instance);
227 0           $cc->{StartTime} = $response->{'1.3.6.1.4.1.9.9.96.1.1.1.1.11.' . $instance};
228 0           $response = $session->get_request('1.3.6.1.4.1.9.9.96.1.1.1.1.12.' . $instance);
229 0           $cc->{EndTime} = $response->{'1.3.6.1.4.1.9.9.96.1.1.1.1.12.' . $instance};
230 0           $session->set_request('1.3.6.1.4.1.9.9.96.1.1.1.1.14.' . $instance, INTEGER, 6);
231 0           return bless $cc, $class
232             # Error
233             } elsif ($response->{'1.3.6.1.4.1.9.9.96.1.1.1.1.10.' . $instance} == 4) {
234 0           $response = $session->get_request('1.3.6.1.4.1.9.9.96.1.1.1.1.13.' . $instance);
235 0           $session->set_request('1.3.6.1.4.1.9.9.96.1.1.1.1.14.' . $instance, INTEGER, 6);
236 0           $Cisco::SNMP::LASTERROR = "IOS $params{protocol} `$params{op}' FAILED - " . $ioserr{$response->{'1.3.6.1.4.1.9.9.96.1.1.1.1.13.' . $instance}};
237             return undef
238 0           } else {
239 0           $Cisco::SNMP::LASTERROR = "Cannot determine success or failure";
240             return undef
241 0           }
242             }
243              
244             sub ccStartTime {
245 0     0 1   my $self = shift;
246             return $self->{StartTime}
247 0           }
248              
249             sub ccEndTime {
250 0     0 1   my $self = shift;
251             return $self->{EndTime}
252 0           }
253              
254             ##################################################
255             # End Public Module
256             ##################################################
257              
258             ##################################################
259             # Start Private subs
260             ##################################################
261              
262             # Return:
263             # -1 = error
264             # 0 = DONE
265             # 1 = continue
266             sub _config_copy {
267              
268 0     0     my ($params, $session, $instance) = @_;
269              
270 0           my $response;
271 0           my %caterr = (
272             1 => "In Progress",
273             2 => "Success",
274             3 => "No Response",
275             4 => "Too Many Retries",
276             5 => "No Buffers",
277             6 => "No Processes",
278             7 => "Bad Checksum",
279             8 => "Bad Length",
280             9 => "Bad Flash",
281             10 => "Server Error",
282             11 => "User Cancelled",
283             12 => "Wrong Code",
284             13 => "File Not Found",
285             14 => "Invalid TFTP Host",
286             15 => "Invalid TFTP Module",
287             16 => "Access Violation",
288             17 => "Unknown Status",
289             18 => "Invalid Storage Device",
290             19 => "Insufficient Space On Storage Device",
291             20 => "Insufficient Dram Size",
292             21 => "Incompatible Image"
293             );
294              
295 0 0         if ($params->{catos}) {
296 0           $response = $session->set_request('1.3.6.1.4.1.9.5.1.5.1.0', OCTET_STRING, $params->{server});
297 0           $response = $session->set_request('1.3.6.1.4.1.9.5.1.5.2.0', OCTET_STRING, $params->{file});
298 0           $response = $session->set_request('1.3.6.1.4.1.9.5.1.5.3.0', INTEGER, 1);
299 0 0         if ($params->{op} eq 'put') {
300 0           $response = $session->set_request('1.3.6.1.4.1.9.5.1.5.4.0', INTEGER, 2)
301             } else {
302 0           $response = $session->set_request('1.3.6.1.4.1.9.5.1.5.4.0', INTEGER, 3)
303             }
304              
305             # loop and check response - error if timeout
306 0           $response = $session->get_request('1.3.6.1.4.1.9.5.1.5.5.0');
307 0           my $loop = 0;
308 0           while ($response->{'1.3.6.1.4.1.9.5.1.5.5.0'} == 1) {
309 0           $response = $session->get_request('1.3.6.1.4.1.9.5.1.5.5.0');
310 0 0         if ($loop++ == $params->{timeout}) {
311 0           $Cisco::SNMP::LASTERROR = "CatOS TFTP `$params->{op}' FAILED - timeout during completion verification";
312 0           return -1
313             }
314 0           sleep 1
315             }
316              
317 0 0         if ($response->{'1.3.6.1.4.1.9.5.1.5.5.0'} == 2) {
318 0           return 0
319             } else {
320 0           $Cisco::SNMP::LASTERROR = "CatOS TFTP `$params->{op}' FAILED - " . $caterr{$response->{'1.3.6.1.4.1.9.5.1.5.5.0'}};
321 0           return -1
322             }
323              
324             # IOS
325             } else {
326             # ccCopyEntryRowStatus (5 = createAndWait, 6 = destroy)
327 0           $response = $session->set_request('1.3.6.1.4.1.9.9.96.1.1.1.1.14.' . $instance, INTEGER, 6);
328 0           $response = $session->set_request('1.3.6.1.4.1.9.9.96.1.1.1.1.14.' . $instance, INTEGER, 5);
329              
330             # ccCopyProtocol
331 0           $response = $session->set_request('1.3.6.1.4.1.9.9.96.1.1.1.1.2.' . $instance, INTEGER, $PROTO{$params->{protocol}});
332              
333 0 0         if (!defined $response) {
334 0           $Cisco::SNMP::LASTERROR = "IOS TFTP `$params->{op}' NOT SUPPORTED - trying old way";
335 0 0         if ($params->{protocol} ne 'tftp') {
336 0           $Cisco::SNMP::LASTERROR = "Old way does not support `$params->{protocol}'";
337 0           return -1
338             }
339 0 0         if ($params->{family} == $AF_INET6) {
340 0           $Cisco::SNMP::LASTERROR = "IOS TFTP `$params->{op}' old way does not support IPv6";
341 0           return -1
342             }
343 0 0         if ($params->{op} eq 'put') {
344             $response = $session->set_request('1.3.6.1.4.1.9.2.1.50.' . $params->{server}, OCTET_STRING, $params->{file})
345 0           } else {
346             $response = $session->set_request('1.3.6.1.4.1.9.2.1.55.' . $params->{server}, OCTET_STRING, $params->{file})
347 0           }
348 0 0         if (defined $response) {
349 0           return 0
350             } else {
351 0           $Cisco::SNMP::LASTERROR = "IOS TFTP `$params->{op}' FAILED (new and old)";
352 0           return -1
353             }
354             }
355              
356 0 0         if ($params->{protocol} ne 'tftp') {
357 0           $response = $session->set_request('1.3.6.1.4.1.9.9.96.1.1.1.1.7.' . $instance, OCTET_STRING, $params->{username});
358 0 0         if ($params->{protocol} ne 'rcp') {
359 0           $response = $session->set_request('1.3.6.1.4.1.9.9.96.1.1.1.1.8.' . $instance, OCTET_STRING, $params->{password});
360             }
361             }
362              
363             # ccCopySourceFileType [.3] (1 = networkFile, 3 = startupConfig, 4 = runningConfig)
364             # ccCopyDestFileType [.4] (1 = networkFile, 3 = startupConfig, 4 = runningConfig)
365 0 0         if ($params->{op} eq 'put') {
366 0           $response = $session->set_request('1.3.6.1.4.1.9.9.96.1.1.1.1.3.' . $instance, INTEGER, 1);
367             $response = $session->set_request('1.3.6.1.4.1.9.9.96.1.1.1.1.4.' . $instance, INTEGER, $params->{dest})
368 0           } else {
369 0           $response = $session->set_request('1.3.6.1.4.1.9.9.96.1.1.1.1.3.' . $instance, INTEGER, $params->{source});
370 0           $response = $session->set_request('1.3.6.1.4.1.9.9.96.1.1.1.1.4.' . $instance, INTEGER, 1)
371             }
372             # New way
373             # ccCopyServerAddressType (1 = IPv4, 2 = IPv6)
374 0 0         $response = $session->set_request('1.3.6.1.4.1.9.9.96.1.1.1.1.15.' . $instance, INTEGER, ($params->{family} == AF_INET) ? 1 : 2);
375              
376 0 0         if (defined $response) {
377             # ccCopyServerAddressRev1
378             $response = $session->set_request('1.3.6.1.4.1.9.9.96.1.1.1.1.16.' . $instance, OCTET_STRING, $params->{server})
379 0           } else {
380             # Deprecated
381             # ccCopyServerAddress
382 0 0         if ($params->{family} == $AF_INET6) {
383 0           $Cisco::SNMP::LASTERROR = "ccCopyServerAddressRev1 not supported (requried for IPv6)";
384 0           return -1
385             }
386             $response = $session->set_request('1.3.6.1.4.1.9.9.96.1.1.1.1.5.' . $instance, IPADDRESS, $params->{server})
387 0           }
388             # ccCopyFileName
389             $response = $session->set_request('1.3.6.1.4.1.9.9.96.1.1.1.1.6.' . $instance, OCTET_STRING, $params->{file})
390 0           }
391 0           return 1
392             }
393              
394             ##################################################
395             # End Private subs
396             ##################################################
397              
398             1;
399              
400             __END__