File Coverage

blib/lib/BlueCoat/SGOS.pm
Criterion Covered Total %
statement 265 371 71.4
branch 109 210 51.9
condition 19 36 52.7
subroutine 23 29 79.3
pod 8 8 100.0
total 424 654 64.8


line stmt bran cond sub pod time code
1             package BlueCoat::SGOS;
2 2     2   29873 use strict;
  2         5  
  2         64  
3 2     2   9 use warnings;
  2         5  
  2         58  
4 2     2   2077 use Data::Dumper;
  2         21231  
  2         141  
5 2     2   3014 use Date::Parse;
  2         23809  
  2         286  
6 2     2   2120 use LWP::UserAgent;
  2         109425  
  2         86  
7             require HTTP::Request;
8 2     2   1960 use HTTP::Request::Common qw/POST/;
  2         4800  
  2         16049  
9              
10             our %_URL = (
11             'archconf_expanded' => '/archconf_expanded.txt',
12             'contentfilter_status' => '/ContentFilter/Status',
13             'sysinfo' => '/SYSINFO',
14             'send_command' =>
15             '/Secure/Local/console/install_upload_action/cli_post_setup.txt'
16             );
17              
18             our %defaults = (
19             'appliancehost' => 'proxy',
20             'applianceport' => 8082,
21             'applianceusername' => 'admin',
22             'appliancepassword' => 'password',
23             'applianceconnectmode' => 'https',
24             'debuglevel' => 0,
25             );
26              
27             =head1 NAME
28              
29             BlueCoat::SGOS - A module to interact with Blue Coat SGOS-based devices.
30              
31             =head1 VERSION
32              
33             Version 1.05
34              
35             =cut
36              
37             our $VERSION = '1.05';
38              
39             =head1 SYNOPSIS
40              
41             This module interacts with Blue Coat SGOS-based devices. Right
42             now, this is limited to parsing of the 'sysinfo' data from the
43             device.
44              
45             use strict; #always!
46             use BlueCoat::SGOS;
47             my $bc = BlueCoat::SGOS->new(
48             'appliancehost' => 'swg.example.com',
49             'applianceport' => 8082,
50             'applianceuser' => 'admin',
51             'appliancepassword' => 'password'
52             );
53             $bc->get_sysinfo();
54             $bc->parse_sysinfo();
55              
56             # or from a file
57             my $bc = BlueCoat::SGOS->new();
58             $bc->get_sysinfo_from_file('/path/to/file.sysinfo');
59             $bc->parse_sysinfo();
60              
61             # or from a data structure
62             # in this case, $sysinfodata already contains sysinfo data
63             my $bc = BlueCoat::SGOS->new();
64             $bc->get_sysinfo_from_data($sysinfodata);
65             $bc->parse_sysinfo();
66              
67             my $sysinfodata = $bc->{'sgos_sysinfo'};
68             my $sgosversion = $bc->{'sgosversion'};
69             my $sgosreleaseid = $bc->{'sgosreleaseid'};
70             my $serialnumber = $bc->{'serialnumber'};
71             my $modelnumber = $bc->{'modelnumber'};
72             my $sysinfotime = $bc->{'sysinfotime'};
73              
74             # Hardware section of the sysinfo file
75             my $hwinfo = $bc->{'sgos_sysinfo_sect'}{'Hardware Information'};
76              
77             # Software configuration (i.e. show configuration)
78             my $swconfig = $bc->{'sgos_sysinfo_sect'}{'Software Configuration'};
79              
80              
81             =head1 SUBROUTINES/METHODS
82              
83             Below are methods for BlueCoat::SGOS.
84             =cut
85              
86             =head2 new
87              
88             Creates a new BlueCoat::SGOS object. Can be passed one of the following:
89              
90             appliancehost
91             applianceport
92             applianceusername
93             appliancepassword
94             applianceconnectmode (one of http or https)
95             debuglevel
96              
97             =cut
98              
99             sub new {
100 1     1 1 2617 my $class = shift;
101 1         3 my $self = {};
102 1         4 bless($self, $class);
103 1         35 my %args = (%defaults, @_);
104              
105 1         7 $self->{'_appliancehost'} = $args{'appliancehost'};
106 1         3 $self->{'_applianceport'} = $args{'applianceport'};
107 1         4 $self->{'_applianceusername'} = $args{'applianceusername'};
108 1         9 $self->{'_appliancepassword'} = $args{'appliancepassword'};
109 1         3 $self->{'_applianceconnectmode'} = $args{'applianceconnectmode'};
110 1         3 $self->{'_debuglevel'} = $args{'debuglevel'};
111 1 50 33     26 if ( $self->{'_appliancehost'}
      33        
      33        
      33        
112             && $self->{'_applianceport'}
113             && $self->{'_applianceconnectmode'}
114             && $self->{'_applianceusername'}
115             && $self->{'_appliancepassword'}) {
116              
117 1 50       4 if ($self->{'_applianceconnectmode'} eq 'https') {
    0          
118 1         6 $self->{'_applianceurlbase'} =
119             q#https://#
120             . $self->{'_appliancehost'} . q#:#
121             . $self->{'_applianceport'};
122             }
123             elsif ($self->{'_applianceconnectmode'} eq 'http') {
124 0         0 $self->{'_applianceurlbase'} =
125             q#http://#
126             . $self->{'_appliancehost'} . q#:#
127             . $self->{'_applianceport'};
128             }
129             }
130              
131 1         3 return $self;
132             }
133              
134             sub _create_ua {
135 0     0   0 my $self = shift;
136 0         0 $self->{'_lwpua'} = LWP::UserAgent->new();
137 0         0 $self->{'_lwpua'}->agent("BlueCoat-SGOS/$VERSION");
138 0         0 $self->{'_lwpua'}->ssl_opts(
139             'SSL_verify_mode' => 0,
140             'verify_hostname' => 0,
141             );
142              
143             }
144              
145             =head2 get_sysinfo
146              
147             Takes no parameters, but instead fetches the sysinfo from the
148             appliance specified in the constructor.
149              
150             $bc->get_sysinfo();
151              
152             =cut
153              
154             sub get_sysinfo {
155 0     0 1 0 my $self = shift;
156              
157 0 0       0 if ($self->{'_debuglevel'} > 0) {
158 0         0 print 'URLBASE=' . $self->{'_applianceurlbase'} . "\n";
159 0         0 print 'Getting '
160             . $self->{'_applianceurlbase'}
161             . $_URL{'sysinfo'} . "\n";
162             }
163 0 0       0 if (!defined($self->{'_lwpua'})) {
164 0         0 $self->_create_ua();
165             }
166 0         0 my $request =
167             HTTP::Request->new('GET',
168             $self->{'_applianceurlbase'} . $_URL{'sysinfo'});
169 0         0 $request->authorization_basic($self->{'_applianceusername'},
170             $self->{'_appliancepassword'});
171 0         0 my $response = $self->{'_lwpua'}->request($request);
172              
173 0 0       0 if ($response->is_error) {
174 0         0 return 0;
175             }
176             else {
177 0         0 $self->{'sgos_sysinfo'} = $response->content;
178 0         0 $self->{'sgos_sysinfo'} =~ s/\r\n/\n/gi;
179 0 0       0 if ($self->{'_debuglevel'} > 0) {
180 0         0 print 'status=' . $response->status_line . "\n";
181             }
182             }
183 0 0       0 if ($self->{'sgos_sysinfo'}) {
184 0         0 return 1;
185             }
186             else {
187 0         0 return 0;
188             }
189             }
190              
191             =head2 get_sysinfo_from_file
192              
193             Takes one parameter: the filename of a sysinfo file on the disk. Use this
194             instead of logging in over the network.
195              
196             $bc->get_sysinfo_from_file('sysinfo.filename.here');
197              
198             =cut
199              
200             sub get_sysinfo_from_file {
201 1     1 1 399 my $self = shift;
202 1         2 my $filename = shift;
203 1 50       4 if ($self->{'_debuglevel'} > 0) {
204 0         0 print "sub:get_sysinfo_from_file, filename=$filename\n";
205             }
206 1 50       26 if (-f $filename) {
207 1         36 open my $FSDFLKFJ, q{<} , $filename;
208              
209             # slurp
210             {
211 1         1 local $/ = undef;
  1         3  
212 1         6112 $self->{'sgos_sysinfo'} = <$FSDFLKFJ>;
213 1         4511 $self->{'sgos_sysinfo'} =~ s/\r\n/\n/gi;
214             }
215 1         31 close $FSDFLKFJ;
216              
217 1 50       13 if ($self->{'sgos_sysinfo'}) {
218 1         31 return 1;
219             }
220             else {
221 0         0 return 0;
222             }
223             }
224             else {
225              
226             # no filename specified
227 0         0 return 0;
228             }
229             }
230              
231             =head2 get_sysinfo_from_data
232              
233             Takes one parameter: a scalar that contains sysinfo data.
234             Use this instead of logging in over the network.
235              
236             $bc->get_sysinfo_from_data($sysinfodata);
237              
238             =cut
239              
240             sub get_sysinfo_from_data {
241 0     0 1 0 my $self = shift;
242 0         0 my $data = shift;
243 0 0       0 if ($self->{'_debuglevel'} > 0) {
244 0         0 print "sub:get_sysinfo_from_data\n";
245             }
246 0         0 $self->{'sgos_sysinfo'} = $data;
247 0         0 $self->{'sgos_sysinfo'} =~ s/\r\n/\n/gi;
248 0 0       0 if ($self->{'sgos_sysinfo'}) {
249 0         0 return 1;
250             }
251             else {
252 0         0 return 0;
253             }
254             }
255              
256             =head2 parse_sysinfo
257              
258             Takes no parameters. Tells the object to parse the sysinfo
259             data and populate the object variables.
260              
261             =cut
262              
263             sub parse_sysinfo {
264 1     1 1 2 my $self = shift;
265 1 50       6 if ($self->{'_debuglevel'} > 0) {
266 0         0 print "parse_sysinfo\n";
267             }
268 1         7436 my @split_sysinfo =
269             split(
270             /__________________________________________________________________________/,
271             $self->{'sgos_sysinfo'}
272             );
273 1         31 $self->{'_sgos_sysinfo_split_count'} = $#split_sysinfo;
274              
275             # init the % var
276 1         7 $self->{'sgos_sysinfo_sect'}{'_ReportInfo'} = $split_sysinfo[0];
277              
278             # Populate the sysinfo version
279             # As of 6.2.2011, these are the known versions:
280             # Version 4.6
281             # Version 5.0
282             # Version 6.0
283             # Version 6.1
284             # Version 7.0
285 1         6 ($self->{'_sysinfoversion'}) =
286             $self->{'sgos_sysinfo_sect'}{'_ReportInfo'} =~ m/Version (\d+\.\d+)/;
287              
288             # Loop through each section of the split sysinfo
289 1         8 foreach (1 .. $#split_sysinfo) {
290 113         186 my $chunk = $split_sysinfo[$_];
291 113         40693 my @section = split(/\n/, $chunk);
292 113         8091 chomp @section;
293              
294             # the first 2 lines are junk
295 113         152 shift @section;
296 113         132 shift @section;
297 113         256 my $sectionname = shift @section;
298              
299 113 100       277 if ($sectionname eq 'Software Configuration') {
300              
301             # get rid of 3 lines from top and 1 from bottom
302 1         2 shift @section;
303 1         3 shift @section;
304 1         1 shift @section;
305 1         3 pop @section;
306             }
307 113 100       215 if ($sectionname eq 'TCP/IP Routing Table') {
308 1         3 shift @section;
309 1         1 shift @section;
310 1         18 shift @section;
311 1         2 shift @section;
312 1         2 shift @section;
313             }
314              
315             # throw away the next line, it contains the URL for the source data
316 113         116 shift @section;
317 113         30894 my $data = join("\n", @section);
318 113         9439 $self->{'sgos_sysinfo_sect'}{$sectionname} = $data;
319             }
320              
321             # parse version
322 1         12 $self->_parse_sgos_version();
323              
324             # parse releaseid
325 1         5 $self->_parse_sgos_releaseid();
326              
327             # parse serial number
328 1         15 $self->_parse_serial_number();
329              
330             # parse sysinfo time
331 1         6 $self->_parse_sysinfo_time();
332              
333             # parse last reboot time
334 1         862 $self->_parse_reboot_time();
335              
336             # parse model
337 1         5 $self->_parse_model_number();
338              
339             # parse the configuration
340 1 50       6 if ($self->{'sgos_sysinfo_sect'}{'Software Configuration'}) {
341 1         5 $self->_parse_swconfig;
342 1         13 $self->{'sysinfo_type'} = 'sysinfo';
343             }
344             else {
345 0         0 $self->{'sysinfo_type'} = 'sysinfo_snapshot';
346             }
347              
348             # parse VPM-CPL and VPM-XML
349 1         9 $self->_parse_vpm();
350              
351             # parse the static bypass list
352 1         8 $self->_parse_static_bypass();
353              
354             # parse the appliance name
355 1         13 $self->_parse_appliance_name();
356              
357             # parse the network information
358 1         156 $self->_parse_network();
359              
360             # parse the ssl accelerator info
361 1         6 $self->_parse_ssl_accelerator();
362              
363             # parse the default gateway
364 1         5 $self->_parse_default_gateway();
365              
366             # parse the route table
367 1         7 $self->_parse_route_table();
368              
369 1         1028 return 1;
370             }
371              
372             # Find appliance-name
373             # located in the Software Configuration
374             # looks like:
375             # appliance-name "ProxySG 210 4609077777"
376             # limited to 127 characters
377             # e.g.: % String exceeds allowed length (127)
378             #
379             sub _parse_appliance_name {
380 1     1   2 my $self = shift;
381 1 50       7 if ($self->{'_debuglevel'} > 0) {
382 0         0 print "_parse_swconfig\n";
383             }
384 1 50       8 if (defined($self->{'sgos_sysinfo_sect'}{'Software Configuration'})) {
385 1         79 (undef, $self->{'appliance-name'}) =
386             $self->{'sgos_sysinfo_sect'}{'Software Configuration'} =~
387             m/(appliance-name|hostname) (.+)$/im;
388 1         9 $self->{'appliance-name'} =~ s/^\"//;
389 1         5 $self->{'appliance-name'} =~ s/\"$//;
390              
391 1 50       5 if ($self->{'_debuglevel'} > 0) {
392 0         0 print "appliancename=$self->{'appliance-name'}\n";
393             }
394             }
395             }
396              
397             # model
398             # Model: 200-B
399             sub _parse_model_number {
400 1     1   2 my $self = shift;
401 1 50       6 if ($self->{'_debuglevel'} > 0) {
402 0         0 print "_parse_model_number\n";
403             }
404              
405             #210-5 (unsupported configuration)
406             #
407 1 50       7 if (defined($self->{'sgos_sysinfo_sect'}{'Hardware Information'})) {
408 1         7 ($self->{'modelnumber'}) =
409             $self->{'sgos_sysinfo_sect'}{'Hardware Information'} =~
410             m/Model:\s(.+)/im;
411 1 50       7 if ($self->{'modelnumber'} =~ m/unsupported configuration/i) {
412 0         0 $self->{'modelnumber'} =~ s/\s*\(unsupported configuration\)\s*//ig;
413 0         0 $self->{'supported_configuration'} = 0;
414             }
415             else {
416 1         3 $self->{'supported_configuration'} = 1;
417             }
418             }
419             }
420              
421             # get network
422             # Network:
423             # Interface 0:0: Bypass 10/100 with no link (MAC 00:d0:83:04:ae:fc)
424             # Interface 0:1: Bypass 10/100 running at 100 Mbps full duplex (MAC 00:d0:83:04:ae:fd)
425             sub _parse_network {
426 1     1   4 my $self = shift;
427 1 50       5 if ($self->{'_debuglevel'} > 0) {
428 0         0 print "_parse_network\n";
429             }
430 1 50       6 if (defined($self->{'sgos_sysinfo_sect'}{'Hardware Information'})) {
431 1         8 my ($netinfo) =
432             $self->{'sgos_sysinfo_sect'}{'Hardware Information'} =~
433             m/Network:(.+)Accelerators/ism;
434 1         5 my @s = split(/\n/, $netinfo);
435 1         3 chomp @s;
436 1         3 foreach (@s) {
437 3         6 my $line = $_;
438 3         12 my ($interface) = $line =~ m/Interface\s+(.+)\:\s/im;
439 3         10 my ($mac) = $line =~ m/\(MAC\s(.+)\)/im;
440 3         6 my ($running) = $line =~ m/running\sat\s(.+)\s\(MAC/im;
441 3         3 my $capabilities;
442              
443             #Interface 0:0: Intel Gigabit running at 1 Gbps full duplex (MAC 00:e0:81:79:a5:1a)
444             #Interface 2:0: Bypass 10/100/1000 with no link (MAC 00:e0:ed:0b:67:e6)
445 3 100       8 if ($line =~ m/running at/) {
446 1         18 ($capabilities) =
447             $line =~ m/Interface\s$interface\:\s\w+(.+)\s+running at/;
448             }
449 3 100       8 if ($line =~ m/with no link/) {
450 1         32 ($capabilities) =
451             $line =~ m/Interface\s$interface\:\s\w+(.+)\s+with no link/;
452             }
453 3 100       10 if ($capabilities) {
454 2         8 $capabilities =~ s/\s+//ig;
455             }
456 3 100 66     14 if ($interface && $capabilities) {
457 2         9 $self->{'interface'}{$interface}{'capabilities'} =
458             $capabilities;
459             }
460              
461             #print "Running=$running\n";
462 3 100 66     15 if ($interface && $mac) {
463 2         4 $self->{'interface'}{$interface}{'mac'} = $mac;
464             }
465 3 100 100     13 if ($interface && $running) {
466 1         2 $self->{'interface'}{$interface}{'linkstatus'} = $running;
467             }
468 3 100 100     15 if ($interface && !$running) {
469 1         4 $self->{'interface'}{$interface}{'linkstatus'} = 'no link';
470             }
471              
472             #print "interface=$interface, mac=$mac\n";
473             }
474             }
475              
476             # supplement from swconfig/networking
477             #print "getting supplemental networking info\n";
478 1         2 my @t;
479              
480             #if (defined($self->{'sgos_swconfig_section'}{'networking'} ) ) {
481 1 50       6 if (defined($self->{'sgos_swconfig_section'}{'networking'})) {
482 1         20 @t = split(/\n/, $self->{'sgos_swconfig_section'}{'networking'});
483 1         6 chomp @t;
484             }
485              
486 1 50       29 if (defined($self->{'sgos_sysinfo_sect'}{'Software Configuration'})) {
487 1 50       7 if ($#t < 2) {
488 0         0 @t =
489             split(/\n/,
490             $self->{'sgos_sysinfo_sect'}{'Software Configuration'});
491             }
492             }
493              
494             #}
495              
496 1         2 my $interface;
497 1         1 my ($ip, $netmask);
498 1         4 foreach (@t) {
499 29         43 my $line = $_;
500              
501 29 100       58 if ($line =~ m/interface (.+)\;/i) {
502 2         10 ($interface) = $line =~ m/^interface (\d+\:?\d*\.*\d*)/i;
503             }
504              
505             # sgos5, ip address and subnet mask are on SAME line
506 29 100       52 if ($line =~ m/ip-address/) {
507              
508 1         8 ($ip, $netmask) =
509             $line =~
510             m/^ip-address\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) *(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*/i;
511 1 50       4 if (defined($ip)) {
512 1         4 $ip =~ s/\s+//gi;
513             }
514 1 50       3 if (defined($netmask)) {
515 1         2 $netmask =~ s/\s+//gi;
516             }
517             }
518 29 50       49 if ($line =~ m/subnet-mask/) {
519 0         0 ($netmask) =
520             $line =~ m/^subnet-mask *(.{1,3}\..{1,3}\..{1,3}\..{1,3})/i;
521 0         0 $netmask =~ s/\s+//gi;
522             }
523              
524 29 100       63 if (defined($interface)) {
525 6 100 66     35 if (length($interface) > 1 && $ip && $netmask) {
      66        
526 1         3 $self->{'interface'}{$interface}{'ip'} = $ip;
527 1         3 $self->{'interface'}{$interface}{'netmask'} = $netmask;
528 1         1 $interface = undef;
529 1         3 $ip = undef;
530             }
531             }
532              
533             }
534             }
535              
536             sub _parse_swconfig {
537 1     1   3 my $self = shift;
538 1 50       4 if ($self->{'_debuglevel'} > 0) {
539 0         0 print "_parse_swconfig\n";
540             }
541 1         1211 my @split_swconfig =
542             split(/\n/, $self->{'sgos_sysinfo_sect'}{'Software Configuration'});
543              
544             # only applies to SGOS >5
545 1         168 my $sectionname = '';
546 1         4 foreach (1 .. $#split_swconfig) {
547 2181         3402 my $line = $split_swconfig[$_];
548 2181         2686 chomp $line;
549 2181 100       5342 if ($line =~ m/!- BEGIN/) {
    100          
550 25         99 ($sectionname) = $line =~ m/!- BEGIN (.+)/;
551             }
552             elsif ($line =~ m/!- END/) {
553 25         331 next;
554             }
555             else {
556 2131 100       4339 if (defined($self->{'sgos_swconfig_section'}{$sectionname})) {
557 2116         11789 $self->{'sgos_swconfig_section'}{$sectionname} =
558             $self->{'sgos_swconfig_section'}{$sectionname} . $line . "\n";
559             }
560             else {
561 15         64 $self->{'sgos_swconfig_section'}{$sectionname} = $line . "\n";
562             }
563             }
564              
565             }
566              
567             }
568              
569             sub _parse_static_bypass {
570 1     1   2 my $self = shift;
571 1 50       8 if (defined($self->{'sgos_sysinfo_sect'}{'Software Configuration'})) {
572 1         1290 my @lines =
573             split(/\n/, $self->{'sgos_sysinfo_sect'}{'Software Configuration'});
574 1         163 my $have_static_bypass;
575 1         3 foreach my $line (@lines) {
576 2182 50       4790 if ($line =~ m/static-bypass/) {
    50          
577 0         0 $have_static_bypass = 1;
578             }
579             elsif ($have_static_bypass) {
580 0 0       0 if ($line =~ m/exit/) {
581 0         0 last;
582             }
583             else {
584 0         0 $line =~ s/^add //i;
585 0 0       0 if (defined($self->{'static-bypass'})) {
586 0         0 $self->{'static-bypass'} =
587             $self->{'static-bypass'} . $line . "\n";
588             }
589             else {
590 0         0 $self->{'static-bypass'} = $line . "\n";
591             }
592             }
593             }
594             }
595             }
596             }
597              
598             sub _parse_vpm {
599 1     1   2 my $self = shift;
600 1 50       9 if (defined($self->{'sgos_sysinfo_sect'}{'Software Configuration'})) {
601 1         1060 my @lines =
602             split(/\n/, $self->{'sgos_sysinfo_sect'}{'Software Configuration'});
603 1         159 my $have_vpm_cpl;
604             my $have_vpm_xml;
605              
606 1         3 foreach my $line (@lines) {
607 1440 100       2956 if ($line =~ m/^inline policy vpm-cpl \"*end-(\d+)-inline\"*/) {
    100          
608 1         8 ($have_vpm_cpl) =
609             $line =~ m/^inline policy vpm-cpl \"*end-(\d+)-inline\"*/;
610             }
611             elsif ($have_vpm_cpl) {
612 93 100       277 if ($line =~ m/end-$have_vpm_cpl-inline/i) {
613 1         5 last;
614             }
615             else {
616 92 100       153 if (defined($self->{'vpm-cpl'})) {
617 91         359 $self->{'vpm-cpl'} = $self->{'vpm-cpl'} . $line . "\n";
618             }
619             else {
620 1         7 $self->{'vpm-cpl'} = $line . "\n";
621             }
622             }
623             }
624              
625             }
626              
627 1         3 foreach my $line (@lines) {
628 2181 100       4874 if ($line =~ m/^inline policy vpm-xml \"*end-(\d+)-inline\"*/) {
    100          
629 1         6 ($have_vpm_xml) =
630             $line =~ m/^inline policy vpm-xml \"*end-(\d+)-inline\"*/;
631             }
632             elsif ($have_vpm_xml) {
633 740 100       1781 if ($line =~ m/end-$have_vpm_xml-inline/i) {
634 1         308 last;
635             }
636             else {
637 739 100       1338 if (defined($self->{'vpm-xml'})) {
638 738         3058 $self->{'vpm-xml'} = $self->{'vpm-xml'} . $line . "\n";
639             }
640             else {
641 1         5 $self->{'vpm-xml'} = $line . "\n";
642             }
643             }
644             }
645              
646             }
647             }
648              
649 1 50 33     133 return 1 if ($self->{'vpm-cpl'} && $self->{'vpm-xml'});
650             }
651              
652             =head2 vpmcpl
653              
654             Displays the VPM-CPL data. Note that this does not currently return the
655             local, central, or forwarding policies.
656              
657             =cut
658              
659             sub vpmcpl {
660 0     0 1 0 my $self = shift;
661 0         0 return $self->{'vpm-cpl'};
662             }
663              
664             =head2 vpmxml
665              
666             Displays the VPM-XML data.
667              
668             =cut
669              
670             sub vpmxml {
671 0     0 1 0 my $self = shift;
672 0         0 return $self->{'vpm-xml'};
673             }
674              
675             sub _parse_default_gateway {
676 1     1   1 my $self = shift;
677 1 50       5 if ($self->{'_debuglevel'} > 0) {
678             }
679              
680 1         1 my @s;
681 1 50       5 if (defined($self->{'sgos_swconfig_section'}{'networking'})) {
682 1         23 my @s = split(/\n/, $self->{'sgos_swconfig_section'}{'networking'});
683 1         12 chomp @s;
684             }
685 1 50       6 if (defined($self->{'sgos_sysinfo_sect'}{'Software Configuration'})) {
686 1 50       5 if ($#s < 2) {
687 1         1108 @s =
688             split(/\n/,
689             $self->{'sgos_sysinfo_sect'}{'Software Configuration'});
690             }
691             }
692 1 50       165 if ($#s > 0) {
693 1         2 foreach my $line (@s) {
694 2182 100       4199 if ($line =~ m/ip-default-gateway/) {
695 1         8 ($self->{'ip-default-gateway'}) = $line =~
696             m/^ip-default-gateway +(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/;
697             }
698             }
699             }
700              
701             }
702              
703             sub _parse_route_table {
704 1     1   2 my $self = shift;
705 1 50       12 if ($self->{'_debuglevel'} > 0) {
706 0         0 print "_parse_route_table: begin\n";
707             }
708              
709             #inline static-route-table "end-398382495-inline"
710             #; IP-Address Subnet Mask Gateway
711             #172.16.0.0 255.240.0.0 172.20.144.1
712             #end-398382495-inline
713 1 50       6 if (defined($self->{'sgos_sysinfo_sect'}{'TCP/IP Routing Table'})) {
714 1         2 my @r;
715 1 50       5 if ($self->{'sgos_sysinfo_sect'}{'TCP/IP Routing Table'}) {
716 1         7 $self->{'routetable'} =
717             $self->{'sgos_sysinfo_sect'}{'TCP/IP Routing Table'};
718             }
719             else {
720 0         0 @r =
721             split(/\n/,
722             $self->{'sgos_sysinfo_sect'}{'Software Configuration'});
723             }
724 1         2 my $marker;
725 1         4 foreach my $line (@r) {
726 0 0       0 if ($line =~ m/inline static-route-table \"end-\d+-inline\"/i) {
727 0         0 ($marker) =
728             $line =~ m/inline static-route-table \"end-(\d+)-inline\"/i;
729             }
730 0 0       0 if ($self->{'_debuglevel'} > 0) {
731 0         0 print "_parse_route_table: marker=$marker\n";
732             }
733 0 0       0 if (defined($marker)) {
734 0 0       0 if ($line =~ m/end-$marker-inline/o) {
735 0         0 $marker = undef;
736             }
737             }
738 0 0 0     0 if ($marker && $line !~ /$marker/i) {
739 0 0       0 if ($line =~ m/^\s*?\;/) {
740 0         0 next;
741             }
742 0 0       0 if ($line =~
743             m/\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/
744             ) {
745 0 0       0 if (defined($self->{'static-route-table'})) {
746 0         0 $self->{'static-route-table'} =
747             $self->{'static-route-table'} . $line . "\n";
748             }
749             else {
750 0         0 $self->{'static-route-table'} = $line . "\n";
751             }
752              
753             }
754             }
755             }
756             }
757              
758             }
759              
760             sub _parse_serial_number {
761 1     1   5 my $self = shift;
762 1 50       5 if ($self->{'_debuglevel'} > 0) {
763 0         0 print "_parse_sgos_serial_number\n";
764             }
765 1 50       5 if (defined($self->{'sgos_sysinfo_sect'}{'Version Information'})) {
766 1         8 ($self->{'serialnumber'}) =
767             $self->{'sgos_sysinfo_sect'}{'Version Information'} =~
768             m/Serial\snumber\sis\s(\d+)/isx;
769             }
770             }
771              
772             sub _parse_ssl_accelerator {
773 1     1   2 my $self = shift;
774 1 50       4 if ($self->{'_debuglevel'} > 0) {
775 0         0 print "_parse_ssl_accelerator\n";
776             }
777              
778             # SSL Accelerators
779             # looks like:
780             # Accelerators: none
781             # or
782             # Accelerators:
783             # Internal: Cavium CN1010 Security Processor
784             # Internal: Cavium CN501 Security Processor
785             # Internal: Broadcom 5825 Security Processor
786             #
787 1 50       5 if (defined($self->{'sgos_sysinfo_sect'}{'Hardware Information'})) {
788 1         7 my ($acceleratorinfo) =
789             $self->{'sgos_sysinfo_sect'}{'Hardware Information'} =~
790             m/(Accelerators\:.+)/ism;
791 1         3 my @a = split(/\n/, $acceleratorinfo);
792              
793             #print "There are $#a lines\n";
794             # if 1 line, then no SSL accelerator
795 1 50       4 if ($#a == 0) {
796 1         4 $self->{'ssl-accelerator'} = 'none';
797             }
798 1 50       4 if ($#a > 0) {
799 0         0 ($self->{'ssl-accelerator'}) = $a[1] =~ m/\s+(.+)/;
800             }
801             }
802              
803             # print "DEBUG: acceleratorinfo=$acceleratorinfo\n";
804             #print "DEBUG: ssl-accelerator=$self->{'ssl-accelerator'}\n";
805             }
806              
807             # sysinfo time
808             # time on this file
809             # The current time is Mon Nov 23, 2009 18:48:38 GMT (SystemTime 438547718)
810             # The current time is Sat Mar 7, 2009 16:57:30 GMT (SystemTime 415990650)
811             sub _parse_sysinfo_time {
812 1     1   2 my $self = shift;
813 1 50       3 if ($self->{'_debuglevel'} > 0) {
814 0         0 print "_parse_sysinfo_time\n";
815             }
816 1 50       11 if (defined($self->{'sgos_sysinfo_sect'}{'Version Information'})) {
817 1         9 ($self->{'sysinfotime'}) =
818             $self->{'sgos_sysinfo_sect'}{'Version Information'} =~
819             m/^The current time is (.+) \(/im;
820 1         10 $self->{'sysinfotime_epoch'} = str2time($self->{'sysinfotime'});
821             }
822             }
823              
824             sub _parse_reboot_time {
825 1     1   4 my $self = shift;
826 1 50       7 if ($self->{'_debuglevel'} > 0) {
827 0         0 print "_parse_reboot_time\n";
828             }
829              
830             # Calculate hardware reboot time
831             # The ProxySG Appliance was last hardware rebooted 1 days, 5 hours, 55 minutes, and 0 seconds ago.
832 1 50       6 if (defined($self->{'sgos_sysinfo_sect'}{'Version Information'})) {
833 1         11 ($self->{'hardware_reboot'}) =
834             $self->{'sgos_sysinfo_sect'}{'Version Information'} =~
835             m/The ProxySG Appliance was last hardware rebooted (.*)$/m;
836 1         4 ($self->{'hardware_reboot_day'}) =
837             $self->{'hardware_reboot'} =~ m/(\d+) day/;
838 1 50       6 if (!defined($self->{'hardware_reboot_day'})) {
839 1         3 $self->{'hardware_reboot_day'} = 0;
840             }
841 1         7 ($self->{'hardware_reboot_hour'}) =
842             $self->{'hardware_reboot'} =~ m/(\d+) hour/;
843 1 50       6 if (!defined($self->{'hardware_reboot_hour'})) {
844 0         0 $self->{'hardware_reboot_hour'} = 0;
845             }
846 1         7 ($self->{'hardware_reboot_minute'}) =
847             $self->{'hardware_reboot'} =~ m/(\d+) minute/;
848 1 50       6 if (!defined($self->{'hardware_reboot_minute'})) {
849 0         0 $self->{'hardware_reboot_minute'} = 0;
850             }
851 1         7 ($self->{'hardware_reboot_second'}) =
852             $self->{'hardware_reboot'} =~ m/(\d+) second/;
853 1 50       9 if (!defined($self->{'hardware_reboot_second'})) {
854 0         0 $self->{'hardware_reboot_second'} = 0;
855             }
856 1         8 $self->{'hardware_reboot_seconds_total'} =
857             ($self->{'hardware_reboot_day'} * 24 * 3600) +
858             ($self->{'hardware_reboot_hour'} * 3600) +
859             ($self->{'hardware_reboot_minute'} * 60) +
860             $self->{'hardware_reboot_second'};
861              
862             # The ProxySG Appliance was last software rebooted 1 days, 5 hours, 55 minutes, and 1 seconds ago.
863              
864 1         7 ($self->{'software_reboot'}) =
865             $self->{'sgos_sysinfo_sect'}{'Version Information'} =~
866             m/The ProxySG Appliance was last software rebooted (.*)$/m;
867 1         4 ($self->{'software_reboot_day'}) =
868             $self->{'software_reboot'} =~ m/(\d+) day/;
869 1 50       5 if (!defined($self->{'software_reboot_day'})) {
870 1         2 $self->{'software_reboot_day'} = 0;
871             }
872 1         8 ($self->{'software_reboot_hour'}) =
873             $self->{'software_reboot'} =~ m/(\d+) hour/;
874 1 50       5 if (!defined($self->{'software_reboot_hour'})) {
875 0         0 $self->{'software_reboot_hour'} = 0;
876             }
877 1         7 ($self->{'software_reboot_minute'}) =
878             $self->{'software_reboot'} =~ m/(\d+) minute/;
879 1 50       5 if (!defined($self->{'software_reboot_minute'})) {
880 0         0 $self->{'software_reboot_minute'} = 0;
881             }
882 1         8 ($self->{'software_reboot_second'}) =
883             $self->{'software_reboot'} =~ m/(\d+) second/;
884 1 50       5 if (!defined($self->{'software_reboot_second'})) {
885 0         0 $self->{'software_reboot_second'} = 0;
886             }
887 1         7 $self->{'software_reboot_seconds_total'} =
888             ($self->{'software_reboot_day'} * 24 * 3600) +
889             ($self->{'software_reboot_hour'} * 3600) +
890             ($self->{'software_reboot_minute'} * 60) +
891             $self->{'software_reboot_second'};
892             }
893             }
894              
895             sub _parse_sgos_releaseid {
896 1     1   3 my $self = shift;
897 1 50       4 if ($self->{'_debuglevel'} > 0) {
898 0         0 print "_parse_sgos_releaseid\n";
899             }
900              
901             # parse SGOS version, SGOS releaseid, and serial number
902             # SGOS release ID
903 1 50       5 if (defined($self->{'sgos_sysinfo_sect'}{'Version Information'})) {
904 1         10 ($self->{'sgosreleaseid'}) =
905             $self->{'sgos_sysinfo_sect'}{'Version Information'} =~
906             m/Release\sid:\s(\d+)/isx;
907             }
908             }
909              
910             sub _parse_sgos_version {
911 1     1   4 my $self = shift;
912 1 50       6 if ($self->{'_debuglevel'} > 0) {
913 0         0 print "_parse_sgos_version\n";
914             }
915              
916             # parse SGOS version, SGOS releaseid, and serial number
917 1 50       5 if ($self->{'_debuglevel'} > 0) {
918 0         0 print "VERSION INFO SECTION:\n";
919 0         0 print $self->{'sgos_sysinfo_sect'}{'Version Information'} . "\n";
920             }
921              
922             # SGOS version
923             # #Version Information
924             # URL_Path /SYSINFO/Version
925             # Blue Coat Systems, Inc., ProxySG Appliance Version Information
926             # Version: SGOS 4.2.10.1
927             #
928 1 50       7 if (defined($self->{'sgos_sysinfo_sect'}{'Version Information'})) {
929 1         75 ($self->{'sgosversion'}) =
930             $self->{'sgos_sysinfo_sect'}{'Version Information'} =~
931             m/Version:\sSGOS\s(\d+\.\d+\.\d+\.\d+)/im;
932 1 50       7 if ($self->{'_debuglevel'} > 0) {
933 0           print "SGOS version = $self->{'sgosversion'}\n";
934             }
935             }
936             }
937              
938             =head2 send_command
939              
940             Takes one parameter: a scalar that contains configuration commands to send to the appliance.
941             This command is executed in configuration mode.
942              
943             my $output = $bc->send_command('show version');
944             # or
945             my $commands =qq{
946             int 0:0
947             speed 100
948             };
949             my $output = $bc->send_command($commands);
950              
951             =cut
952              
953             sub send_command {
954 0     0 1   my $self = shift;
955 0           my $command = shift;
956 0 0         if ($self->{'_debuglevel'} > 0) {
957 0           print "begin sub:send_command\n";
958 0           print "command=$command\n";
959             }
960 0 0         if (!defined($self->{'_lwpua'})) {
961 0           $self->_create_ua();
962             }
963 0           my $request = POST $self->{'_applianceurlbase'} . $_URL{'send_command'},
964             Content_Type => 'form-data',
965             'Content' => ['file' => $command];
966 0           $request->authorization_basic($self->{'_applianceusername'},
967             $self->{'_appliancepassword'});
968 0           my $response = $self->{'_lwpua'}->request($request);
969 0           my $content;
970 0 0         if ($response->is_success) {
971 0           $content = $response->content;
972             }
973             else {
974 0           die 'error';
975             }
976 0           $content =~ s/\r//ig;
977 0           return $content;
978             }
979              
980             =head2 Other Data
981              
982             Other data that is directly accessible in the object:
983              
984             Appliance Name: $bc->{'appliance-name'}
985             Model Number: $bc->{'modelnumber'}
986             Serial Number: $bc->{'serialnumber'}
987             SGOS Version: $bc->{'sgosversion'}
988             Release ID: $bc->{'sgosreleaseid'}
989             Default Gateway: $bc->{'ip-default-gateway'}
990             Sysinfo Time: $bc->{'sysinfotime'}
991             Accelerator Info: $bc->{'ssl-accelerator'}
992              
993             The software configuration can be retrieved as follows:
994             $bc->{'sgos_sysinfo_sect'}{'Software Configuration'}
995              
996             Other sections that can be retrieved:
997             $bc->{'sgos_sysinfo_sect'}{'Software Configuration'}
998             $bc->{'sgos_sysinfo_sect'}{'ADN Compression Statistics'}
999             $bc->{'sgos_sysinfo_sect'}{'ADN Configuration'}
1000             $bc->{'sgos_sysinfo_sect'}{'ADN Node Info'}
1001             $bc->{'sgos_sysinfo_sect'}{'ADN Sizing Peers'}
1002             $bc->{'sgos_sysinfo_sect'}{'ADN Sizing Statistics'}
1003             $bc->{'sgos_sysinfo_sect'}{'ADN Tunnel Statistics'}
1004             $bc->{'sgos_sysinfo_sect'}{'AOL IM Statistics'}
1005             $bc->{'sgos_sysinfo_sect'}{'Access Log Objects'}
1006             $bc->{'sgos_sysinfo_sect'}{'Access Log Statistics'}
1007             $bc->{'sgos_sysinfo_sect'}{'Authenticator Memory Statistics'}
1008             $bc->{'sgos_sysinfo_sect'}{'Authenticator Realm Statistics'}
1009             $bc->{'sgos_sysinfo_sect'}{'Authenticator Total Realm Statistics'}
1010             $bc->{'sgos_sysinfo_sect'}{'CCM Configuration'}
1011             $bc->{'sgos_sysinfo_sect'}{'CCM Statistics'}
1012             $bc->{'sgos_sysinfo_sect'}{'CIFS Memory Usage'}
1013             $bc->{'sgos_sysinfo_sect'}{'CIFS Statistics'}
1014             $bc->{'sgos_sysinfo_sect'}{'CPU Monitor'}
1015             $bc->{'sgos_sysinfo_sect'}{'CacheEngine Main'}
1016             $bc->{'sgos_sysinfo_sect'}{'Configuration Change Events'}
1017             $bc->{'sgos_sysinfo_sect'}{'Content Filter Status'}
1018             $bc->{'sgos_sysinfo_sect'}{'Core Image'}
1019             $bc->{'sgos_sysinfo_sect'}{'Crypto Statistics'}
1020             $bc->{'sgos_sysinfo_sect'}{'DNS Cache Statistics'}
1021             $bc->{'sgos_sysinfo_sect'}{'DNS Query Statistics'}
1022             $bc->{'sgos_sysinfo_sect'}{'Disk 1'}
1023             ... and up to Disk 10, in some cases
1024             $bc->{'sgos_sysinfo_sect'}{'Endpoint Mapper Internal Statistics'}
1025             $bc->{'sgos_sysinfo_sect'}{'Endpoint Mapper Statistics'}
1026             $bc->{'sgos_sysinfo_sect'}{'Endpoint Mapper database contents'}
1027             $bc->{'sgos_sysinfo_sect'}{'FTP Statistics'}
1028             $bc->{'sgos_sysinfo_sect'}{'Forwarding Settings'}
1029             $bc->{'sgos_sysinfo_sect'}{'Forwarding Statistics Per IP'}
1030             $bc->{'sgos_sysinfo_sect'}{'Forwarding Summary Statistics'}
1031             $bc->{'sgos_sysinfo_sect'}{'Forwarding health check settings'}
1032             $bc->{'sgos_sysinfo_sect'}{'Forwarding health check statistics'}
1033             $bc->{'sgos_sysinfo_sect'}{'HTTP Configuration'}
1034             $bc->{'sgos_sysinfo_sect'}{'HTTP Main'}
1035             $bc->{'sgos_sysinfo_sect'}{'HTTP Requests'}
1036             $bc->{'sgos_sysinfo_sect'}{'HTTP Responses'}
1037             $bc->{'sgos_sysinfo_sect'}{'Hardware Information'}
1038             $bc->{'sgos_sysinfo_sect'}{'Hardware sensors'}
1039             $bc->{'sgos_sysinfo_sect'}{'Health Monitor'}
1040             $bc->{'sgos_sysinfo_sect'}{'Health check entries'}
1041             $bc->{'sgos_sysinfo_sect'}{'Health check statistics'}
1042             $bc->{'sgos_sysinfo_sect'}{'ICP Hosts'}
1043             $bc->{'sgos_sysinfo_sect'}{'ICP Settings'}
1044             $bc->{'sgos_sysinfo_sect'}{'ICP Statistics'}
1045             $bc->{'sgos_sysinfo_sect'}{'IM Configuration'}
1046             $bc->{'sgos_sysinfo_sect'}{'Kernel Statistics'}
1047             $bc->{'sgos_sysinfo_sect'}{'Licensing Statistics'}
1048             $bc->{'sgos_sysinfo_sect'}{'MAPI Client Statistics'}
1049             $bc->{'sgos_sysinfo_sect'}{'MAPI Conversation Client Errors'}
1050             $bc->{'sgos_sysinfo_sect'}{'MAPI Conversation Other Errors'}
1051             $bc->{'sgos_sysinfo_sect'}{'MAPI Conversation Server Errors'}
1052             $bc->{'sgos_sysinfo_sect'}{'MAPI Errors'}
1053             $bc->{'sgos_sysinfo_sect'}{'MAPI Internal Statistics'}
1054             $bc->{'sgos_sysinfo_sect'}{'MAPI Server Statistics'}
1055             $bc->{'sgos_sysinfo_sect'}{'MAPI Statistics'}
1056             $bc->{'sgos_sysinfo_sect'}{'MMS Configuration'}
1057             $bc->{'sgos_sysinfo_sect'}{'MMS General'}
1058             $bc->{'sgos_sysinfo_sect'}{'MMS Statistics'}
1059             $bc->{'sgos_sysinfo_sect'}{'MMS Streaming Statistics'}
1060             $bc->{'sgos_sysinfo_sect'}{'MSN IM Statistics'}
1061             $bc->{'sgos_sysinfo_sect'}{'OPP Services'}
1062             $bc->{'sgos_sysinfo_sect'}{'OPP Statistics'}
1063             $bc->{'sgos_sysinfo_sect'}{'P2P Statistics'}
1064             $bc->{'sgos_sysinfo_sect'}{'Persistent Statistics'}
1065             $bc->{'sgos_sysinfo_sect'}{'Policy Statistics'}
1066             $bc->{'sgos_sysinfo_sect'}{'Policy'}
1067             $bc->{'sgos_sysinfo_sect'}{'Priority 1 Events'}
1068             $bc->{'sgos_sysinfo_sect'}{'Quicktime Configuration'}
1069             $bc->{'sgos_sysinfo_sect'}{'Quicktime Statistics'}
1070             $bc->{'sgos_sysinfo_sect'}{'RIP Statistics'}
1071             $bc->{'sgos_sysinfo_sect'}{'Real Configuration'}
1072             $bc->{'sgos_sysinfo_sect'}{'Real Statistics'}
1073             $bc->{'sgos_sysinfo_sect'}{'Refresh Statistics'}
1074             $bc->{'sgos_sysinfo_sect'}{'SCSI Disk Statistics'}
1075             $bc->{'sgos_sysinfo_sect'}{'SOCKS Gateways Settings'}
1076             $bc->{'sgos_sysinfo_sect'}{'SOCKS Gateways Statistics'}
1077             $bc->{'sgos_sysinfo_sect'}{'SOCKS Proxy Statistics'}
1078             $bc->{'sgos_sysinfo_sect'}{'SSL Proxy Certificate Cache'}
1079             $bc->{'sgos_sysinfo_sect'}{'SSL Statistics'}
1080             $bc->{'sgos_sysinfo_sect'}{'Security processor Statistics'}
1081             $bc->{'sgos_sysinfo_sect'}{'Server Side persistent connections'}
1082             $bc->{'sgos_sysinfo_sect'}{'Services Management Statistics'}
1083             $bc->{'sgos_sysinfo_sect'}{'Services Per-service Statistics'}
1084             $bc->{'sgos_sysinfo_sect'}{'Services Proxy Statistics'}
1085             $bc->{'sgos_sysinfo_sect'}{'Software Configuration'}
1086             $bc->{'sgos_sysinfo_sect'}{'System Memory Statistics'}
1087             $bc->{'sgos_sysinfo_sect'}{'TCP/IP ARP Information'}
1088             $bc->{'sgos_sysinfo_sect'}{'TCP/IP Listening list'}
1089             $bc->{'sgos_sysinfo_sect'}{'TCP/IP Malloc Information'}
1090             $bc->{'sgos_sysinfo_sect'}{'TCP/IP Routing Table'}
1091             $bc->{'sgos_sysinfo_sect'}{'TCP/IP Statistics'}
1092             $bc->{'sgos_sysinfo_sect'}{'Threshold Monitor Statistics'}
1093             $bc->{'sgos_sysinfo_sect'}{'Version Information'}
1094             $bc->{'sgos_sysinfo_sect'}{'WCCP Configuration'}
1095             $bc->{'sgos_sysinfo_sect'}{'WCCP Statistics'}
1096             $bc->{'sgos_sysinfo_sect'}{'Yahoo IM Statistics'}
1097            
1098              
1099             The details for interface 0:0 are stored here:
1100             IP address: $bc->{'interface'}{'0:0'}{'ip'}
1101             Netmask: $bc->{'interface'}{'0:0'}{'netmask'}
1102             MAC address: $bc->{'interface'}{'0:0'}{'mac'}
1103             Link status: $bc->{'interface'}{'0:0'}{'linkstatus'}
1104             Capabilities: $bc->{'interface'}{'0:0'}{'capabilities'}
1105              
1106             You can retrieve the interface names like this:
1107             my @interfaces = keys %{$bc->{'interface'}};
1108              
1109             The route table can be retrieved as follows:
1110             $bc->{'sgos_sysinfo_sect'}{'TCP/IP Routing Table'}
1111              
1112             The static route table can be retrieved as follows:
1113             $bc->{'static-route-table'}
1114              
1115             The WCCP configuration can be retrieved as follows:
1116             $bc->{'sgos_sysinfo_sect'}{'WCCP Configuration'}
1117              
1118              
1119             =cut
1120              
1121             =head1 AUTHOR
1122              
1123             Matthew Lange
1124              
1125             =head1 BUGS
1126              
1127             Please report any bugs or feature requests through
1128             the web interface at L. I will be notified, and then you'll
1129             automatically be notified of progress on your bug as I make changes.
1130              
1131              
1132              
1133              
1134             =head1 SUPPORT
1135              
1136             You can find documentation for this module with the perldoc command.
1137              
1138             perldoc BlueCoat::SGOS
1139              
1140              
1141             You can also look for information at:
1142              
1143             =over 4
1144              
1145             =item * RT: CPAN's request tracker
1146              
1147             L
1148              
1149             =item * AnnoCPAN: Annotated CPAN documentation
1150              
1151             L
1152              
1153             =item * CPAN Ratings
1154              
1155             L
1156              
1157             =item * Search CPAN
1158              
1159             L
1160              
1161             =back
1162              
1163              
1164             =head1 LICENSE
1165              
1166             Copyright (C) 2008-2012 Matthew Lange
1167              
1168             This program is free software; you can redistribute it and/or modify it
1169             under the terms of the GNU General Public License version 2 as
1170             published by the Free Software Foundation.
1171              
1172             =cut
1173              
1174             1; # End of BlueCoat::SGOS
1175              
1176             __DATA__