File Coverage

blib/lib/RINO/Client.pm
Criterion Covered Total %
statement 12 94 12.7
branch 0 30 0.0
condition 0 2 0.0
subroutine 4 10 40.0
pod n/a
total 16 136 11.7


line stmt bran cond sub pod time code
1             package RINO::Client;
2              
3 1     1   23426 use 5.008008;
  1         3  
  1         30  
4 1     1   4 use strict;
  1         2  
  1         29  
5 1     1   4 use warnings;
  1         5  
  1         58  
6              
7             our $VERSION = '0.03';
8             $VERSION = eval $VERSION; # see L
9              
10 1     1   923 use Module::Pluggable require => 1;
  1         17661  
  1         6  
11             require XML::IODEF;
12              
13             # Preloaded methods go here.
14              
15             sub _plugins {
16 0     0     my @plugs = plugins();
17 0           foreach (@plugs){
18 0           $_ = lc($_);
19 0           $_ =~ s/rino::client::plugin:://;
20             }
21 0           return(@plugs);
22             }
23              
24             sub new {
25 0     0     my ($class,%args) = (shift,@_);
26 0           my $self = {};
27 0           bless($self,$class);
28 0 0         if($args{'iodef'}){
29 0           $self->to_hash($args{'iodef'});
30             }
31 0           return($self);
32             }
33              
34             sub write_out {
35 0     0     my $self = shift;
36 0   0       my $plugin = shift || 'csv';
37              
38 0           $plugin = 'RINO::Client::Plugin::'.ucfirst($plugin);
39 0           eval "require $plugin";
40 0 0         die($@) if($@);
41              
42 0           my $ref = $self->to_simple();
43 0           return $plugin->write_out($ref);
44             }
45              
46             sub to_hash {
47 0     0     my $self = shift;
48 0           my $xml = shift;
49 0 0         return($self->{'_tree'}) if(defined($self->{'_tree'}));
50              
51 0 0         return unless($xml);
52 0           my $iodef = XML::IODEF->new();
53 0 0         $iodef->in($xml) || return('invalid iodef object',undef);
54 0           $self->{'_xml'} = $iodef;
55 0           $self->{'_tree'} = $iodef->to_tree();
56 0           return(undef,$self->{'_tree'});
57             }
58              
59             sub to_simple {
60 0     0     my $self = shift;
61 0           my $xml = shift;
62 0           my $hash = $self->to_hash($xml);
63 0           my @incidents;
64 0           my @header = ['IncidentID','Description','Address','DetectTime','Port','Destination','AdditionalData'];
65              
66 0           $hash = $hash->{'Incident'};
67 0 0         if(ref($hash) eq 'HASH'){
68 0           push(@incidents,$hash);
69             } else {
70 0           @incidents = @{$hash};
  0            
71             }
72              
73             #only pass back the header info if we're being called from a plugin
74 0           my $caller = caller();
75 0           my @return_array;
76 0 0         if($caller =~ /Client$/){
77 0           @return_array = @header;
78             }
79              
80 0           foreach my $ri (@incidents) {
81             ## embedded " in CSV needs to be ""
82 0           $ri->{IncidentID}{content} =~ s/"/""/g;
83 0           $ri->{Description} =~ s/"/""/g;
84              
85             ## within each Incident there may be one or more EventData, "normalize"
86 0           my $re = $ri->{'EventData'};
87 0           my @events_array = ();
88 0 0         if(ref($re) eq 'HASH') { push(@events_array,$re); } else { @events_array = @{$re}; }
  0            
  0            
  0            
89              
90             ## process each EventData
91 0           foreach my $re (@events_array) {
92 0           $re->{DetectTime} =~ s/"/""/g;
93 0           $re->{Flow}{System}{Node}{Address}{content} =~ s/"/""/g;
94 0 0         if (exists $re->{Flow}{System}{Service}{Port}) {
95 0           $re->{Flow}{System}{Service}{Port} =~ s/"/""/g;
96             } else {
97 0           $re->{Flow}{System}{Service}{Port} = '';
98             }
99              
100             ## within each EventData there may be zero or more AdditionalData
101             ## if "destination address" is one of those, it will have it's own position in the CSV
102             ## all others will be combined into paired values (JSON-like) and placed in one position in the CSV
103 0           my $destination = '';
104 0           my $additional;
105              
106 0 0         if (exists $re->{AdditionalData}) {
107             ## "normalize"
108 0           my $ra = $re->{AdditionalData};
109 0           my @additionaldata_array = ();
110 0 0         if(ref($ra) eq 'HASH') { push(@additionaldata_array,$ra); } else { @additionaldata_array = @{$ra}; }
  0            
  0            
  0            
111              
112             ## process each AdditionalData
113 0           foreach my $a (@additionaldata_array) {
114             ## if "destination address", then hold separately, otherwise accumulate pairs in $additional
115 0 0         if ($a->{meaning} eq 'destination address') {
116 0           $destination = $a->{content};
117             } else {
118 0           $additional .= qq|"$a->{meaning}":"$a->{content}", |;
119             }
120             }
121             ## if there is additiona, remove trailing comma and wrap in braces
122 0 0         if ($additional) { $additional =~ s/, $//; $additional = '{ '.$additional.' }'; }
  0            
  0            
123             }
124 0           push(@return_array, {
125             IncidentID => $ri->{'IncidentID'}{'content'},
126             Description => $ri->{'Description'},
127             Address => $re->{'Flow'}{'System'}{'Node'}{'Address'}{'content'},
128             DetectTime => $re->{'DetectTime'},
129             Port => $re->{'Flow'}{'System'}{'Service'}{'Port'},
130             Destination => $destination,
131             AdditionalData => $additional
132             });
133             }
134             }
135 0           return(\@return_array);
136             }
137            
138              
139             sub sources {
140 0     0     my $self = shift;
141 0 0         return('you must ->to_hash($xml) first',undef) unless($self->{'_tree'});
142 0           my $h = $self->{'_tree'};
143 0           my @events = @{$h->{'Incident'}->{'EventData'}};
  0            
144 0           foreach my $event (@events){
145 0           my $sys = $event->{'Flow'}->{'System'};
146 0 0         next unless($sys->{'category'} eq 'source');
147             }
148              
149             }
150             1;
151             __END__