File Coverage

blib/lib/Iodef/Pb/Simple.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Iodef::Pb::Simple;
2              
3 1     1   31431 use 5.008008;
  1         4  
  1         43  
4 1     1   6 use strict;
  1         2  
  1         34  
5 1     1   4 use warnings;
  1         7  
  1         269  
6              
7             require Exporter;
8              
9             our $VERSION = '0.21';
10             $VERSION = eval $VERSION; # see L
11              
12             our @ISA = qw(Exporter);
13              
14             # Items to export into callers namespace by default. Note: do not export
15             # names by default without a very good reason. Use EXPORT_OK instead.
16             # Do not simply export all your public functions/methods/constants.
17              
18             # This allows declaration use Iodef::Pb::Simple ':all';
19             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
20             # will save memory.
21             our %EXPORT_TAGS = ( 'all' => [ qw(
22             iodef_descriptions iodef_assessments iodef_confidence iodef_impacts iodef_impacts_first
23             iodef_additional_data iodef_systems iodef_addresses iodef_events_additional_data iodef_services
24             iodef_systems_additional_data iodef_normalize_restriction iodef_guid iodef_uuid iodef_malware
25             iodef_bgp iodef_contacts iodef_contacts_cc iodef_normalize_purpose
26             uuid_random uuid_ns is_uuid
27             ) ] );
28              
29             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
30              
31             our @EXPORT = qw(
32            
33             );
34              
35 1     1   784 use Iodef::Pb;
  1         3  
  1         75  
36 1     1   548 use Module::Pluggable require => 1;
  0            
  0            
37             use OSSP::uuid;
38              
39             my @plugins = __PACKAGE__->plugins();
40              
41             sub is_uuid {
42             my $arg = shift;
43             return undef unless($arg && $arg =~ /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/);
44             return(1);
45             }
46              
47             sub uuid_random {
48             my $uuid = OSSP::uuid->new();
49             $uuid->make('v4');
50             my $str = $uuid->export('str');
51             undef $uuid;
52             return($str);
53             }
54              
55             sub uuid_ns {
56             my $source = shift;
57             my $uuid = OSSP::uuid->new();
58             my $uuid_ns = OSSP::uuid->new();
59             $uuid_ns->load('ns::URL');
60             $uuid->make("v3",$uuid_ns,$source);
61             my $str = $uuid->export('str');
62             undef $uuid;
63             return($str);
64             }
65              
66             sub iodef_normalize_restriction {
67             my $restriction = shift || return;
68            
69             if($restriction =~ /^\d$/){
70             return 'private' if($restriction == RestrictionType::restriction_type_private());
71             return 'public' if($restriction == RestrictionType::restriction_type_public());
72             return 'need-to-know' if($restriction == RestrictionType::restriction_type_need_to_know());
73             return 'default' if($restriction == RestrictionType::restriction_type_default());
74             return;
75             } else {
76             for(lc($restriction)){
77             if(/^private$/){
78             $restriction = RestrictionType::restriction_type_private(),
79             last;
80             }
81             if(/^public$/){
82             $restriction = RestrictionType::restriction_type_public(),
83             last;
84             }
85             if(/^need-to-know$/){
86             $restriction = RestrictionType::restriction_type_need_to_know(),
87             last;
88             }
89             if(/^default$/){
90             $restriction = RestrictionType::restriction_type_default(),
91             last;
92             }
93             }
94             }
95             return $restriction;
96             }
97              
98             sub iodef_normalize_purpose {
99             my $thing = shift || return;
100            
101             if($thing =~ /^\d$/){
102             return 'other' if($thing == IncidentType::IncidentPurpose::Incident_purpose_other());
103             return 'mitigation' if($thing == IncidentType::IncidentPurpose::Incident_purpose_mitigation());
104             return 'traceback' if($thing == IncidentType::IncidentPurpose::Incident_purpose_traceback());
105             return 'reporting' if($thing == IncidentType::IncidentPurpose::Incident_purpose_reporting());
106             return;
107             } else {
108             for(lc($thing)){
109             if(/^other/){
110             $thing = IncidentType::IncidentPurpose::Incident_purpose_other(),
111             last;
112             }
113             if(/^mitigation$/){
114             $thing = IncidentType::IncidentPurpose::Incident_purpose_mitigation(),
115             last;
116             }
117             if(/^traceback$/){
118             $thing = IncidentType::IncidentPurpose::Incident_purpose_traceback(),
119             last;
120             }
121             if(/^reporting$/){
122             $thing = IncidentType::IncidentPurpose::Incident_purpose_reporting(),
123             last;
124             }
125             }
126             }
127             return $thing;
128             }
129              
130              
131             sub iodef_descriptions {
132             my $iodef = shift;
133            
134             my @array;
135             foreach my $i (@{$iodef->get_Incident()}){
136             my $desc = $i->get_Description();
137             $desc = [$desc] unless(ref($desc) eq 'ARRAY');
138             push(@array,@$desc);
139             }
140             return(\@array);
141             }
142              
143             sub iodef_contacts {
144             my $iodef = shift;
145            
146             my @array;
147             foreach my $i (@{$iodef->get_Incident()}){
148             my $c = $i->get_Contact();
149             next unless($c);
150             $c = [$c] unless(ref($c) eq 'ARRAY');
151             push(@array,@$c);
152             }
153             return(\@array);
154             }
155              
156             sub iodef_contacts_cc {
157             my $i = shift;
158            
159             return unless($i->get_Contact());
160             my $contacts = (ref($i->get_Contact()) eq 'ContactType') ? [$i->get_Contact()] : $i->get_Contact();
161            
162             my @array;
163             foreach my $c (@$contacts){
164             next unless($c->get_type() == ContactType::ContactRole::Contact_role_cc());
165             push(@array,$c);
166             }
167             return unless(@array);
168             return(\@array);
169             }
170            
171            
172              
173             sub iodef_confidence {
174             my $iodef = shift;
175            
176             if(ref($iodef) eq 'IODEFDocumentType'){
177             $iodef = $iodef->get_Incident();
178             }
179            
180             $iodef = [$iodef] unless(ref($iodef) eq 'ARRAY');
181            
182             my $ret = @{$iodef}[0]->get_Assessment();
183             my @array;
184             foreach my $a (@$ret){
185             push(@array,$a->get_Confidence());
186             }
187             return(\@array);
188             }
189              
190             sub iodef_assessments {
191             my $iodef = shift;
192            
193             return [] unless(ref($iodef) eq 'IncidentType');
194             return $iodef->get_Assessment();
195             }
196              
197             sub iodef_impacts {
198             my $iodef = shift;
199            
200             if(ref($iodef) eq 'IODEFDocumentType'){
201             $iodef = $iodef->get_Incident();
202             };
203             $iodef = [$iodef] unless(ref($iodef) eq 'ARRAY');
204            
205             my $array;
206             foreach my $i (@$iodef){
207             my @local = @{$i->get_Assessment()};
208             push(@$array, map { @{$_->get_Impact()} } @local);
209             }
210             return $array;
211             }
212              
213             sub iodef_impacts_first {
214             my $iodef = shift;
215              
216             return [] unless(ref($iodef) eq 'IncidentType');
217              
218             my $impacts = iodef_impacts($iodef);
219             my $impact = @{$impacts}[0];
220             return($impact);
221             }
222              
223             sub iodef_address_type {
224             my $type = shift;
225            
226             # TODO -- return contstant for net-addr-ipv4, etc.
227            
228             return $type;
229             }
230              
231             sub iodef_addresses {
232             my $iodef = shift;
233             my $type = shift;
234            
235             return unless($iodef);
236            
237             $type = iodef_address_type($type) if($type);
238            
239             if(ref($iodef) eq 'IODEFDocumentType'){
240             $iodef = $iodef->get_Incident();
241             }
242            
243             $iodef = [$iodef] unless(ref($iodef) eq 'ARRAY');
244            
245             my @array;
246             foreach my $i (@$iodef){
247             next unless($i->get_EventData());
248             foreach my $e (@{$i->get_EventData()}){
249             my @flows = (ref($e->get_Flow()) eq 'ARRAY') ? @{$e->get_Flow()} : $e->get_Flow();
250             foreach my $f (@flows){
251             my @systems = (ref($f->get_System()) eq 'ARRAY') ? @{$f->get_System()} : $f->get_System();
252             foreach my $s (@systems){
253             my @nodes = (ref($s->get_Node()) eq 'ARRAY') ? @{$s->get_Node()} : $s->get_Node();
254             foreach my $n (@nodes){
255             my $addresses = $n->get_Address();
256             $addresses = [$addresses] if(ref($addresses) eq 'AddressType');
257             push(@array,@$addresses);
258             }
259             }
260             }
261             }
262             }
263             return(\@array);
264             }
265              
266             sub iodef_bgp {
267             my $iodef = shift;
268            
269             return unless($iodef);
270            
271             if(ref($iodef) eq 'IODEFDocumentType'){
272             $iodef = $iodef->get_Incident();
273             }
274            
275             $iodef = [$iodef] unless(ref($iodef) eq 'ARRAY');
276            
277             my @array;
278             foreach my $i (@$iodef){
279             next unless($i->get_EventData());
280             foreach my $e (@{$i->get_EventData()}){
281             my @flows = (ref($e->get_Flow()) eq 'ARRAY') ? @{$e->get_Flow()} : $e->get_Flow();
282             foreach my $f (@flows){
283             my @systems = (ref($f->get_System()) eq 'ARRAY') ? @{$f->get_System()} : $f->get_System();
284             foreach my $s (@systems){
285             my $x = _additional_data($s);
286             next unless($x);
287             my $hash;
288             foreach (@$x){
289             next unless(lc($_->get_meaning()) =~ /^(asn|asn_desc|prefix|rir|cc)$/);
290             $hash->{$_->get_meaning()} = $_->get_content();
291             }
292             push(@array,$hash);
293             }
294             }
295             }
296             }
297             return unless(@array);
298             return(\@array);
299             }
300              
301             sub iodef_systems {
302             my $iodef = shift;
303            
304             my @array;
305             return unless($iodef->get_EventData());
306             foreach my $e (@{$iodef->get_EventData()}){
307             my @flows = (ref($e->get_Flow()) eq 'ARRAY') ? @{$e->get_Flow()} : $e->get_Flow();
308             foreach my $f (@flows){
309             my @systems = (ref($f->get_System()) eq 'ARRAY') ? @{$f->get_System()} : $f->get_System();
310             push(@array,@systems);
311             }
312             }
313             return(\@array);
314             }
315              
316             sub _additional_data {
317             my $array = shift;
318            
319             $array = [$array] unless(ref($array) eq 'ARRAY');
320             my $return_array;
321             foreach my $e (@$array){
322             next unless($e && $e->get_AdditionalData());
323             my @additional_data = (ref($e->get_AdditionalData()) eq 'ARRAY') ? @{$e->get_AdditionalData()} : $e->get_AdditionalData();
324             push(@$return_array,@additional_data);
325             }
326             return($return_array);
327             }
328              
329             sub iodef_additional_data {
330             my $iodef = shift;
331              
332             if(ref($iodef) eq 'IODEFDocumentType'){
333             $iodef = $iodef->get_Incident();
334             }
335             $iodef = [$iodef] unless(ref($iodef) eq 'ARRAY');
336            
337             my $array = _additional_data($iodef);
338             return($array);
339             }
340              
341             sub iodef_malware {
342             my $iodef = shift;
343              
344             my $ad = iodef_additional_data($iodef);
345             return unless($#{$ad});
346            
347             my $array = [];
348             foreach (@$ad){
349             next unless($_->get_meaning() =~ /^malware hash$/);
350             push(@$array,$_);
351             }
352             return unless($#{$array} > -1);
353             return $array;
354             }
355            
356              
357             sub iodef_events_additional_data {
358             my $iodef = shift;
359            
360             my $array = [];
361             foreach my $i (@{$iodef->get_Incident()}){
362             next unless($i->get_EventData());
363             if(my $ret = _additional_data($i->get_EventData())){
364             push(@$array,@$ret);
365             }
366             }
367            
368             return($array);
369             }
370              
371             sub iodef_systems_additional_data {
372             my $iodef = shift;
373            
374             return unless(ref($iodef) eq 'IncidentType');
375            
376             my $array;
377             foreach my $e (@{$iodef->get_EventData()}){
378             my @flows = (ref($e->get_Flow()) eq 'ARRAY') ? @{$e->get_Flow()} : $e->get_Flow();
379             foreach my $f (@flows){
380             next unless($f->get_System());
381             my @systems = (ref($f->get_System()) eq 'ARRAY') ? @{$f->get_System()} : $f->get_System();
382             if(my $ret = _additional_data($f->get_System())){
383             push(@$array,@$ret);
384             }
385             }
386             }
387             return($array);
388             }
389              
390             sub iodef_guid {
391             my $iodef = shift;
392            
393             return unless(ref($iodef) eq 'IncidentType');
394            
395             my $ad = $iodef->get_AdditionalData();
396             foreach (@$ad){
397             next unless($_->get_meaning() =~ /^guid/);
398             ## TODO -- return array of guids?
399             return $_->get_content();
400             }
401             }
402              
403             sub iodef_uuid {
404             my $iodef = shift;
405             return $iodef->get_IncidentID->get_content();
406             }
407              
408             sub new {
409             my $class = shift;
410             my $args = shift;
411              
412             $args->{'description'} = 'unknown' unless($args->{'description'});
413             $args->{'lang'} = 'EN' unless($args->{'lang'});
414             $args->{'timezone'} = 'UTC' unless($args->{'timezone'});
415            
416             unless(ref($args->{'description'}) eq 'MLStringType'){
417             $args->{'description'} = MLStringType->new({
418             lang => $args->{'lang'},
419             content => $args->{'description'},
420             });
421             }
422              
423             my $pb = IODEFDocumentType->new({
424             lang => $args->{'lang'},
425             # IODEF version
426             version => '1.00',
427             # PB version
428             formatid => '0.01',
429             Incident => [
430             IncidentType->new({
431             Description => [ $args->{'description'} ],
432             }),
433             ],
434             });
435             foreach(@plugins){
436             $_->process($args,$pb);
437             }
438            
439             #die ::Dumper($pb);
440             #####
441             $pb = $class->new_carboncopy($pb,$args);
442              
443             return $pb;
444             }
445              
446             # i dunno that this belongs here, should be higher up the stack maybe
447             # putting here for now till we figure out what to do with it
448             sub new_carboncopy {
449             my $class = shift;
450             my $pb = shift;
451             my $args = shift;
452            
453             return $pb unless($args->{'carboncopy'});
454             return $pb if($args->{'carboncopy_nosplit'} && !$args->{'carboncopy_nosplit'});
455            
456             # setup pointer to the original
457             my $orig_obj = @{$pb->get_Incident()}[0];
458            
459             my %local_args = %$args;
460             my $restriction = $args->{'carboncopy_restriction'} || 'private';
461             $local_args{'restriction'} = $restriction;
462             $local_args{'alternativeid_restriction'} = $restriction;
463            
464             $restriction = iodef_normalize_restriction($restriction) unless($restriction =~ /^\d+$/);
465            
466             my $current_id = @{$pb->get_Incident()}[0]->get_IncidentID();
467             # we need to change the restriction for the altid
468             $current_id = IncidentIDType->new({
469             content => $current_id->get_content(),
470             name => $current_id->get_name(),
471             instance => $current_id->get_instance(),
472             restriction => $restriction,
473             });
474            
475             # setup the array;
476             $pb = [ $pb ];
477              
478             my @cc = split(/,/,$args->{'carboncopy'});
479            
480             delete($local_args{'carboncopy'});
481            
482             my @new_ids;
483             foreach (@cc){
484             $local_args{'guid'} = uuid_ns($_);
485            
486             # create new incident to be pushed into an altid
487             my $new_id = IncidentIDType->new({
488             content => uuid_random(),
489             restriction => $restriction,
490             name => $orig_obj->get_IncidentID->get_name(),
491             });
492            
493             $local_args{'IncidentID'} = $new_id;
494             $local_args{'AlternativeID'} = AlternativeIDType->new({
495             restriction => $restriction,
496             IncidentID => [$current_id],
497             });
498             push(@new_ids, $new_id);
499              
500             # create the new incident
501             my $x = $class->new(\%local_args);
502             push(@$pb,$x);
503             }
504            
505             my $orig_altid = $orig_obj->get_AlternativeID();
506             if($orig_altid){
507             push(@{$orig_altid->{'IncidentID'}},@new_ids);
508             } else {
509             $orig_altid = AlternativeIDType->new({
510             IncidentID => \@new_ids,
511             restriction => $restriction,
512             });
513             }
514            
515             return $pb;
516             }
517              
518             1;
519             __END__