File Coverage

blib/lib/BGPmon/Filter.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 BGPmon::Filter;
2 1     1   39085 use strict;
  1         2  
  1         338  
3 1     1   7 use warnings;
  1         3  
  1         41  
4 1     1   6 use constant FALSE => 0;
  1         7  
  1         92  
5 1     1   6 use constant TRUE => 1;
  1         2  
  1         57  
6 1     1   8931 use BGPmon::Translator::XFB2PerlHash::Simpler;
  0            
  0            
7             use BGPmon::Filter::Prefix;
8             use BGPmon::Filter::Address;
9             use BGPmon::CPM::PList::Manager;
10             use Net::IP;
11             use Regexp::IPv6 qw($IPv6_re);
12             use List::MoreUtils qw(uniq);
13             use Data::Dumper;
14             use threads;
15             use threads::shared;
16              
17             BEGIN{
18             require Exporter;
19             our $VERSION = '2.00';
20             our $AUTOLOAD;
21             our @ISA = qw(Exporter);
22             our @EXPORT_OK = qw(init parse_xml_msg parse_config_file
23             parse_database_config toString filterReset get_error_msg get_error_code
24             matches printFilters get_num_IPv4_prefs get_num_IPv6_prefs
25             get_num_ASes get_num_ip_addrs get_tot_num_filters);
26             }
27              
28              
29             my $progName = $0;
30              
31              
32             # Variables to hold error codes and messages
33             my %error_code;
34             my %error_msg;
35              
36             use constant NO_ERROR_CODE => 0;
37             use constant NO_ERROR_MSG => 'No Error. Relax with some tea.';
38              
39             #Error codes for opening the configuration file.
40             use constant UNOPANABLE_CONFIG_FILE => 520;
41             use constant UNOPANABLE_CONFIG_FILE_MSG => 'Invalid filename given for config
42             file.';
43             #Error codes for parsing the configuration file.
44             use constant INVALID_IPV4_CONFIG => 530;
45             use constant INVALID_IPV4_CONFIG_MSG => "Invalid IPv4 given in config file.";
46             use constant INVALID_IPV6_CONFIG => 531;
47             use constant INVALID_IPV6_CONFIG_MSG => "Invalid IPv6 given in config file.";
48             use constant INVALID_AS_CONFIG => 532;
49             use constant INVALID_AS_CONFIG_MSG => "Invalid AS given in config file.";
50             use constant UNKNOWN_CONFIG => 533;
51             use constant UNKNOWN_CONFIG_MSG => "Invalid line in config file.";
52              
53             #Error codes for parsing the XML file.
54             use constant NO_MSG_GIVEN => 540;
55             use constant NO_MSG_GIVEN_MSG => "No XML message was given.";
56              
57             #Variable to handle locking
58             my $lock = 1;
59             share($lock);
60              
61              
62              
63             # Variables to hold the prefixes we'd like to filter
64             my @v6prefixes = ();
65             my @v4prefixes = ();
66             my %v4prefHash = ();
67             my $v4Count = 0;
68             my %asNumbers = ();
69             my @addresses = ();
70             my $prefixFilename;
71              
72             # Variables to hold prefixes we've found in the latest message that was parsed.
73             my @v4 = ();
74             my @v6 = ();
75             my @as = ();
76              
77              
78             =head1 NAME
79              
80             BGPmon::Filter
81              
82             This module provides information of if a BGP message matches a set of
83             IPv4 or IPv6 prefixes, or if it matches a specific autonymous system number.
84             =cut
85              
86             =head1 SYNOPSIS
87              
88             use BGPmon::Filter;
89              
90             if(BGPmon::Filter::init()){
91              
92             my $err_code = BGPmon::Filter::get_error_code('init');
93            
94             my $err_msg = BGPmon::Filter::get_error_msg('init');
95            
96             print "$err_code : $err_msg\n";
97            
98             exit 1;
99             }
100             if(BGPmon::Filter::parse_config_file('config_file.txt')){
101            
102             my $err_code = BGPmon::Filter::get_error_code('parse_config_file');
103            
104             my $err_msg = BGPmon::Filter::get_error_msg('parse_config_file');
105            
106             print "$err_code : $err_msg\n";
107            
108             exit 1;
109             }
110             my $xml_msg = '...
111              
112             if(BGPmon::Filter::matches($xml_msg)){
113            
114             print "Matches!\n";
115            
116             }
117              
118             else{
119            
120             print "Does not match.\n";
121              
122             }
123              
124             =head1 EXPORT
125              
126             init parse_xml_msg parse_config_file toString filterReset
127             get_error_msg get_error_code matches printFilters
128              
129              
130              
131             =head1 SUBROUTINES/METHODS
132              
133             =head2 init
134              
135             Will initilialize the module an its state variables. This only needs
136             to be called once.
137              
138             =cut
139             sub init{
140             lock($lock);
141             my $fname = 'init';
142              
143             $error_code{$fname} = NO_ERROR_CODE;
144             $error_msg{$fname} = NO_ERROR_MSG;
145              
146             return 0;
147             }
148              
149              
150             =head2 filterReset
151              
152             Resets the module's state values.
153              
154             =cut
155             sub filterReset{
156             lock($lock);
157             my $fname = 'filterReset';
158              
159             foreach(@v6prefixes){
160             $_ = undef;
161             }
162             foreach(@v4prefixes){
163             $_ = undef;
164             }
165             foreach(@addresses){
166             $_ = undef;
167             }
168             foreach(@v4){
169             $_ = undef;
170             }
171             foreach(@v6){
172             $_ = undef;
173             }
174             foreach(@as){
175             $_ = undef;
176             }
177             @v4prefixes = ();
178             %v4prefHash = ();
179             $v4Count = 0;
180             @v6prefixes = ();
181             %asNumbers = ();
182             @addresses = ();
183             @v4 = ();
184             @v6 = ();
185             @as = ();
186              
187              
188             $prefixFilename = undef;
189             %error_code = ();
190             %error_msg = ();
191              
192             $error_code{$fname} = NO_ERROR_CODE;
193             $error_msg{$fname} = NO_ERROR_MSG;
194              
195             return 0;
196             }
197              
198             =head2 get_error_msg
199              
200             Will return the error message of the given function name.
201              
202             Input: A string that contains the function name where an error occured.
203              
204             Output: The message which represents the error stored from that function.
205              
206             =cut
207             sub get_error_msg{
208             lock($lock);
209             my $str = shift;
210             my $fname = 'get_error_msg';
211             my $toReturn = $error_msg{$str};
212             return $toReturn;
213             }
214              
215             =head2 get_error_code
216              
217             Will return the error code of the given function name.
218              
219             Input: A string that represents the function name where an error occured.
220              
221             Output: The code which represents the error stored from that function.
222              
223             =cut
224             sub get_error_code{
225             lock($lock);
226             my $str = shift;
227             my $fname = 'get_error_code';
228             my $toReturn = $error_code{$str};
229             return $toReturn;
230             }
231              
232             #comment
233             #Will check to see if the string passed in is of proper IPv6 format.
234             #cut
235             sub is_IPv6{
236             my $str = shift;
237             my $fname = 'is_IPv6';
238             if(!($str =~ /^$IPv6_re$/)){
239             return FALSE;
240             }
241             return TRUE;
242             }
243              
244              
245              
246              
247             my $prefix_rgx = "\\d+\\.\\d+\\.\\d+\\.\\d+\/\\d+";
248             my $ip_rgx = "\\d+\\.\\d+\\.\\d+\\.\\d+";
249             sub ipv4_chkip($) {
250             #checking to see if it's a prefix or an IPv4 address
251             my ($ip) = $_[0] =~ /($prefix_rgx)/o;
252              
253              
254             #print "Is a prefix\n" if $ip;
255             #print "Not a prefix\n" unless $ip;
256             if($ip){#if a prefix
257              
258             my @parts = split /\//, $ip;
259             my $addr = $parts[0];
260             my $mask = $parts[1];
261             # Check that bytes are in range
262             for (split /\./, $addr ) {
263             return undef if $_ < 0 or $_ > 255;
264             }
265             return undef if $mask < 0 or $mask > 32;
266             return $ip;
267             }
268              
269             else{#if an address
270             ($ip) = $_[0] =~ /($ip_rgx)/o;
271             #print "Is an IP address\n" if $ip;
272             #print "Not an address\n" unless $ip;
273             if($ip){
274             # Check that bytes are in range
275             for (split /\./, $ip ) {
276             return undef if $_ < 0 or $_ > 255;
277             }
278             return $ip;
279             }
280             }
281              
282             return undef;
283             }
284              
285              
286             sub addV4prefixToHash{
287             my $prefix = shift;
288             my $prefObj = shift;
289              
290             my @pieces = split('/',$prefix);
291             my @ips = split /\./, $pieces[0];
292              
293              
294             #firstOct->{secondOct->{thirdOctet->{fourthOctet->{prefixObject
295             if(!exists $v4prefHash{$ips[0]}) {
296             $v4prefHash{$ips[0]} = {};
297             }
298             if(!exists $v4prefHash{$ips[0]}->{$ips[1]}){
299             $v4prefHash{$ips[0]}->{$ips[1]} = {};
300             }
301             if(!exists $v4prefHash{$ips[0]}->{$ips[1]}->{$ips[2]}){
302             $v4prefHash{$ips[0]}->{$ips[1]}->{$ips[2]} = {};
303             }
304             if(!exists $v4prefHash{$ips[0]}->{$ips[1]}->{$ips[2]}->{$ips[3]}){
305             $v4prefHash{$ips[0]}->{$ips[1]}->{$ips[2]}->{$ips[3]} = [];
306             }
307              
308              
309             push($v4prefHash{$ips[0]}->{$ips[1]}->{$ips[2]}->{$ips[3]}, $prefObj);
310             $v4Count += 1;
311             }
312              
313              
314             sub getChildren{
315             my $hashRef = shift;
316              
317             my @toReturn = ();
318              
319             foreach my $key(keys % $hashRef){
320             my $item = $hashRef->{$key};
321             #print "$item\n";
322             if(ref($item) eq 'HASH'){ #still going through the hashes
323             push(@toReturn, @{getChildren($item)});
324             }
325             elsif(ref($item) eq 'ARRAY'){
326             my @toAdd = @{$item};
327             #print Dumper @toAdd;
328             push(@toReturn, @toAdd);
329             }
330             }
331             return \@toReturn;
332             }
333              
334             sub getV4comparisons{
335             my $prefix = shift;
336             my @pieces = split /\//, $prefix;
337             my $ip = $pieces[0];
338             my @ips = split /\./, $ip;
339              
340             if(!exists $v4prefHash{$ips[0]}) {
341             return getChildren(\%v4prefHash);
342             }
343             elsif(!exists $v4prefHash{$ips[0]}->{$ips[1]}) {
344             return getChildren($v4prefHash{$ips[0]});
345             }
346             elsif(!exists $v4prefHash{$ips[0]}->{$ips[1]}->{$ips[2]}) {
347             return getChildren($v4prefHash{$ips[0]}->{$ips[1]});
348             }
349             elsif(!exists $v4prefHash{$ips[0]}->{$ips[1]}->{$ips[2]}->{$ips[3]}) {
350             return getChildren($v4prefHash{$ips[0]}->{$ips[1]}->{$ips[2]});
351             }
352             elsif(exists $v4prefHash{$ips[0]}->{$ips[1]}->{$ips[2]}->{$ips[3]}){
353             #returns the array of prefixes with these four octets
354             my $toReturn = $v4prefHash{$ips[0]}->{$ips[1]}->{$ips[2]}->{$ips[3]};
355             return $toReturn;
356             }
357             else{
358             #TODO make lookup error
359             return undef;
360             }
361             }
362              
363              
364              
365              
366             =head2 parse_config_file
367              
368             Will parse the wanted IPv4 and IPv6 prefixes from a configuration file as well
369             as any autonymous system numbers. These will be stored until
370             BGPmon::Filter::filterReset() is called. This will also aggregate addresses
371             where possible and setup a mult-layer hash lookup system for faster retrieval
372              
373             Input: A string with the location of the configuration file to parse
374              
375             Output: 0 if there is no error
376             1 if an error occured
377              
378              
379             =cut
380             sub parse_config_file{
381             lock($lock);
382             $prefixFilename = shift;
383             my $fname = 'parse_config_file';
384             my $file;
385             my $lineNum = 0;
386             if(!open($file, $prefixFilename)){
387             $error_code{$fname} = UNOPANABLE_CONFIG_FILE;
388             $error_msg{$fname} = UNOPANABLE_CONFIG_FILE_MSG;
389             return 1;
390             }
391              
392             while(my $line = <$file>){
393             $lineNum ++;
394             chomp $line;
395              
396             # Remove any trailing white space.
397             $line =~ s/^s+//g;
398              
399             # If the line starts with a #, skip it.
400             next if ($line =~ /^s*#/);
401              
402             # Skipping the line if it's blank
403             next if ($line eq "");
404              
405              
406             # Splitting the line up
407             my @lineArray = split ' ', $line;
408             my $lineLength = scalar(@lineArray);
409             if($lineLength < 1){
410             $error_code{$fname} = UNKNOWN_CONFIG;
411             $error_msg{$fname} = UNKNOWN_CONFIG_MSG;
412             return 1;
413             }
414              
415              
416             # if this line is an AS number
417             if($lineArray[0] =~ /[aA][sS]/){
418             if($lineArray[1] > 0 and $lineArray[1] < 65536){
419             my $temp = $lineArray[1];
420             $asNumbers{$temp} = 1;
421             }
422             else{
423             $error_code{$fname} = INVALID_AS_CONFIG;
424             $error_msg{$fname} = INVALID_AS_CONFIG_MSG;
425             return 1;
426             }
427             }
428             # if this line is an IPv4 number
429             elsif($lineArray[0] =~ /[iI][pP][vV][4]/){
430             #Making sure whatever is next is either a valid prefix or IPv4 address
431             my $ipcheck = ipv4_chkip($lineArray[1]);
432             unless($ipcheck) {
433             $error_code{$fname} = INVALID_IPV4_CONFIG;
434             $error_msg{$fname} = INVALID_IPV4_CONFIG_MSG.':'.$line;
435             return 1;
436             }
437             #Decerning if we have a prefix or IPv4 address
438             if($ipcheck =~ /\//){ #prefix
439             if(!exists($lineArray[2]) or !$lineArray[2] =~ m/[mMlL][sS]/){
440             $error_code{$fname} = INVALID_IPV4_CONFIG;
441             $error_msg{$fname} = INVALID_IPV4_CONFIG_MSG.':'.$line;
442             return 1;
443             #print "Skippnig $line\n";
444             #next;
445             }
446             # Adding prefix to the list since it's okay
447             my $moreSpecific = $lineArray[2] =~ m/[mM][sS]/;
448             my $temp = new BGPmon::Filter::Prefix(4, $lineArray[1], $moreSpecific);
449             push(@v4prefixes, $temp);
450             }
451             else{#IPv4 address
452             my $temp = new BGPmon::Filter::Address(4,$lineArray[1]);
453             push(@addresses,$temp);
454             }
455             }
456              
457             # if this line is an IPv6 number
458             elsif($lineArray[0] =~ /[iI][pP][vV][6]/){
459             # Ensuring that it's a valid IPv6 number and prefix
460             my @ipv6Addr = split(/\//, $lineArray[1]);
461             my $address = $ipv6Addr[0];
462             my $prefix = $ipv6Addr[1];
463              
464             # Making sure the IPv6 is valid - in any form.
465             if(!is_IPv6($ipv6Addr[0])){
466             $error_code{$fname} = INVALID_IPV6_CONFIG;
467             $error_msg{$fname} = INVALID_IPV6_CONFIG_MSG;
468             return 1;
469             }
470              
471             # Making sure the prefix is valid
472             if($prefix < 0 or $prefix > 128){
473             $error_code{$fname} = INVALID_IPV6_CONFIG;
474             $error_msg{$fname} = INVALID_IPV6_CONFIG_MSG;
475             return 1;
476             }
477              
478             # Adding prefix to the list
479             if(!defined($lineArray[2])){
480             $error_code{$fname} = INVALID_IPV6_CONFIG;
481             $error_msg{$fname} = INVALID_IPV6_CONFIG_MSG;
482             }
483             if(!$lineArray[2] =~ m/[mMlL][sS]/){
484             $error_code{$fname} = INVALID_IPV6_CONFIG;
485             $error_msg{$fname} = INVALID_IPV6_CONFIG_MSG;
486             return 1;
487             }
488             my $moreSpecific = $lineArray[2] =~ m/[mM][sS]/;
489             my $temp = new BGPmon::Filter::Prefix(6, $lineArray[1], $moreSpecific);
490             push(@v6prefixes, $temp);
491             }
492              
493             # if we don't know what this line is
494             else{
495             $error_code{$fname} = UNKNOWN_CONFIG;
496             $error_msg{$fname} = UNKNOWN_CONFIG_MSG;
497             return 1;
498             }
499              
500              
501              
502             }
503              
504             #closing the file
505             close($file);
506             condense_prefs(); #aggregates where possible
507             optimize_prefs(); #puts them in the multilayer hash for faster lookups
508              
509             $error_code{$fname} = NO_ERROR_CODE;
510             $error_msg{$fname} = NO_ERROR_MSG;
511              
512             return 0;
513             }
514              
515              
516              
517             sub parse_database_config{
518             my $listName = shift;
519             my $fname = 'parse_database_config';
520             lock($lock);
521              
522              
523             #getting a list of prefixes
524             my @prefs = BGPmon::CPM::PList::Manager::export2CSV('',$listName);
525             my $size = scalar(@prefs);
526             if($size == 0){
527             #TODO create an error message that has the list size at zero
528             }
529              
530             #resetting the module
531             filterReset();
532              
533             #creating new prefixes
534             foreach(@prefs){
535             my $newPref = $_->prefix();
536             my $moreSpec = $_->watch_more_specifics();
537             if(is_IPv6($newPref)){
538             my $temp = new BGPmon::Filter::Prefix(6, $newPref, $moreSpec);
539             push(@v6prefixes, $temp);
540             }
541             else{
542             my $temp = new BGPmon::Filter::Prefix(4, $newPref, $moreSpec);
543             push(@v4prefixes, $temp);
544             }
545             }
546              
547              
548             #optimizing
549             condense_prefs(); #aggregates where possible
550             optimize_prefs(); #puts them in the multilayer hash for faster lookups
551              
552             $error_code{$fname} = NO_ERROR_CODE;
553             $error_msg{$fname} = NO_ERROR_MSG;
554              
555             return 0;
556              
557             }
558              
559             #puts the prefixes for IPv4 into a multi-layer hash lookup
560             sub optimize_prefs{
561             foreach(@v4prefixes){
562             my $temp = $_;
563             addV4prefixToHash($temp->prefix(), $temp);
564             }
565              
566             #TODO put in error codes
567              
568             return 0;
569             }
570              
571             =head2 get_num_IPv4_prefs
572              
573             Will count the number of IPv4 prefixes it has parsed from the configuration
574             file and return the integer
575              
576             Input: None
577             Output : Integer
578             =cut
579             sub get_num_IPv4_prefs{
580             my $toReturn = scalar(@v4prefixes);
581             return $toReturn;
582             }
583              
584             =head2 get_num_IPv6_prefs
585              
586             Will count the number of IPv6 prefixes it has parsed from the configuration
587             file and return the integer
588              
589             Input: None
590             Output : Integer
591             =cut
592             sub get_num_IPv6_prefs{
593             my $toReturn = scalar(@v6prefixes);
594             return $toReturn;
595             }
596              
597              
598             =head2 get_num_ASes
599              
600             Will count the number of ASes it has parsed from the configuration
601             file and return the integer
602              
603             Input: None
604             Output : Integer
605             =cut
606             sub get_num_ASes{
607             my $toReturn = scalar(keys %asNumbers);
608             return $toReturn;
609             }
610              
611              
612              
613             =head2 get_num_ip_addrs
614              
615             Will count the number of IPv4 addresses it has parsed from the configuration
616             file and return the integer
617              
618             Input: None
619             Output : Integer
620             =cut
621             sub get_num_ip_addrs{
622             my $toReturn = scalar(@addresses);
623             return $toReturn;
624             }
625              
626             =head2 get_total_num_filters
627              
628             Will tally all filters the module will look for per message and return
629             the interger
630              
631             Input: None
632             Output : Integer
633              
634             =cut
635             sub get_total_num_filters{
636             lock($lock);
637             my $toReturn = 0;
638             $toReturn += scalar(@v4prefixes);
639             $toReturn += scalar(@v6prefixes);
640             $toReturn += scalar(%asNumbers);
641             $toReturn += scalar(@addresses);
642             return $toReturn;
643             }
644              
645              
646             #condense__prefs
647             #
648             #Will try to aggregate IPv4 and IPv6 prefixes where possible. This is used to reduce
649             #overhead that the filter script may experience later. Please note that the
650             #parse_config_file must be ran beforehand.
651             #
652             #Input: None
653             #
654             #Output: 0 if there is no error
655             # 1 if an error occured
656             #
657             #
658             sub condense_prefs{
659            
660             ##Starting with IPv4
661             #Will continuously agg. addresses where it can until none are left
662             my $found = TRUE;
663             while($found){
664             $found = FALSE;
665             for( my $i = 0; $i < scalar(@v4prefixes); $i++){
666             my $currPref = $v4prefixes[$i];
667             for(my $k = $i+1; $k < scalar(@v4prefixes); $k++){
668             my $thisPref = $v4prefixes[$k];
669             next if not $currPref->matchSpecific($thisPref);
670              
671             if($currPref->canAggregateWith($thisPref)){
672             my $newPref = $currPref->getAggregate($thisPref);
673             splice @v4prefixes, $k, 1;
674             splice @v4prefixes, $i, 1;
675             my $np = new BGPmon::Filter::Prefix(4,
676             $newPref, $currPref->{moreSpecific});
677             push(@v4prefixes, $np);
678             $found = TRUE;
679             }
680             }
681             }
682             }
683              
684             ##Starting with IPv6
685             #Will continuously agg. addresses where it can until none are left
686             $found = TRUE;
687             while($found){
688             $found = FALSE;
689             for( my $i = 0; $i < scalar(@v6prefixes); $i++){
690             my $currPref = $v6prefixes[$i];
691             for(my $k = $i+1; $k < scalar(@v6prefixes); $k++){
692             my $thisPref = $v6prefixes[$k];
693             next if not $currPref->matchSpecific($thisPref);
694              
695             if($currPref->canAggregateWith($thisPref)){
696             my $newPref = $currPref->getAggregate($thisPref);
697             splice @v6prefixes, $k, 1;
698             splice @v6prefixes, $i, 1;
699             my $np = new BGPmon::Filter::Prefix(6,
700             $newPref, $currPref->{moreSpecific});
701             push(@v6prefixes, $np);
702             $found = TRUE;
703             }
704             }
705             }
706             }
707              
708             return 0;
709             }
710              
711              
712              
713             =head2 printFilters
714              
715             Will print to standard output the filters currently set for the module.
716             For example, if your prefix file looked like
717              
718             #IPv4
719              
720             ipv4 192.168.1.0/24 ls
721              
722             #IPv6
723              
724             ipv6 ::0/32 ms
725              
726             #AS
727              
728             as 1
729              
730             This will print
731              
732             ipv4 192.168.1.0/24 ls
733              
734             ipv6 ::0/32 ms
735              
736             as 1
737              
738             =cut
739              
740             sub printFilters{
741             lock($lock);
742             foreach(@v4prefixes){
743             my $temp = $_->toString();
744             print "$temp\n";
745             }
746             foreach(@v6prefixes){
747             my $temp = $_->toString();
748             print "$temp\n";
749             }
750             foreach(keys %asNumbers){
751             print "$_\n";
752             }
753             foreach(@addresses){
754             my $temp = $_->toString();
755             print "$temp\n";
756             }
757             }
758              
759              
760              
761             =head2 toString
762              
763             Will return a string that prints the most recently filtered prefixes and
764             autonymous system numbers in human-readable format.
765              
766             E.g.,
767             IPv4 prefixes pulled from the message:
768             192.168.1.0/24
769             IPv6 prefixes pulled from the message:
770             (none)
771             AS numbers pulled from the message:
772             12345
773              
774             =cut
775             sub toString{
776             lock($lock);
777             my $fname = 'toString';
778             my $toReturn = "";
779              
780             #Adding v4's
781             $toReturn .= "IPv4 prefixes pulled from the message:\n";
782             if(scalar @v4 == 0){
783             $toReturn .= "(none)\n";
784             }
785             else{
786             foreach(@v4){
787             $toReturn .= "$_\n";
788             }
789             }
790              
791             #Adding v6's
792             #
793             $toReturn .= "IPv6 prefixes pulled from the message:\n";
794             if(scalar @v6 == 0){
795             $toReturn .= "(none)\n";
796             }
797             else{
798             foreach(@v6){
799             $toReturn .= "$_\n";
800             }
801             }
802             #Adding AS's
803             #
804             $toReturn .= "AS numbers pulled from the message:\n";
805             if(scalar @as == 0){
806             $toReturn .= "(none)\n";
807             }
808             else{
809             foreach(@as){
810             $toReturn .= "$_\n";
811             }
812             }
813              
814             return $toReturn;
815              
816             }
817              
818             #comment
819             #
820             #Will reset the most recently filtered prefixes and AS numbers, parse the
821             #message that was sent to it, and store a unique set of prefixes and
822             #AS numbers.
823             #
824             #cut
825             sub parse_xml_msg{
826             lock($lock);
827             my $fname = 'parse_xml_msg';
828             my $xmlMsg = shift;
829              
830             if(!defined($xmlMsg)){
831             $error_code{$fname} = NO_MSG_GIVEN;
832             $error_msg{$fname} = NO_MSG_GIVEN_MSG;
833             return undef;
834             }
835              
836             # A list of all the prefixes and AS's found during searching.
837             my @v4s = ();
838             my @v6s = ();
839             my @ases = ();
840              
841             # The translation of the message
842             my $parseRes = BGPmon::Translator::XFB2PerlHash::Simpler::parse_xml_msg($xmlMsg);
843             if($parseRes){
844             #TODO return new value saying we couldn't parse the message.
845             return 1;
846             }
847              
848             #Checking the withdrawn part of the message
849             my @withs = BGPmon::Translator::XFB2PerlHash::Simpler::extract_withdraw();
850             foreach(@withs){
851             #my $pref = $_->{'content'};
852             my @parts = split(/\//, $_);
853             if(is_IPv6($parts[0])){
854             push(@v6s, $_);
855             }
856             else{
857             push(@v4s, $_);
858             }
859             }
860            
861              
862             #Checking the address parts in NLRI place
863             my @nlris = BGPmon::Translator::XFB2PerlHash::Simpler::extract_nlri();
864             foreach(@nlris){
865             my @parts = split(/\//, $_);
866             if(is_IPv6($parts[0])){
867             push(@v6s, $_);
868             }
869             else{
870             push(@v4s, $_);
871             }
872             }
873              
874              
875             #Checking the MP_NLRI part of MP_REACH_NLRI; skipping the Next Hop addresses
876             my @reach = BGPmon::Translator::XFB2PerlHash::Simpler::extract_mpreach_nlri();
877             foreach(@reach){
878             my @parts = split(/\//, $_);
879             if(is_IPv6($parts[0])){
880             push(@v6s, $_);
881             }
882             else{
883             push(@v4s, $_);
884             }
885             }
886              
887              
888             #Checking the address part of MP_UNREACH_NLRI
889             my @unreach = BGPmon::Translator::XFB2PerlHash::Simpler::extract_mpunreach_nlri();
890             foreach(@unreach){
891             my @parts = split(/\//, $_);
892             if(is_IPv6($parts[0])){
893             push(@v6s, $_);
894             }
895             else{
896             push(@v4s, $_);
897             }
898             }
899              
900              
901              
902             #Checking for the origin in the AS_Path attribute
903             my $origin = BGPmon::Translator::XFB2PerlHash::Simpler::extract_origin();
904             push(@ases, $origin) if defined($origin);
905              
906              
907             @v4 = uniq(@v4s);
908             @v6 = uniq(@v6s);
909             @as = uniq(@ases);
910              
911             return 0; # successful message parsing
912             }
913              
914              
915             =head2 matches
916              
917             Will check to see if the BGPmon message passed to it has maching prefix or AS
918             fields that were given earlier to the module.
919              
920             Input: A BGPmon message in XML format
921              
922             Output: 1 if there was at least one matching filed.
923             0 if no matches were found.
924              
925             =cut
926             sub matches{
927             lock($lock);
928             my $xmlMsg = shift;
929             my $fname = 'matches';
930              
931             if(!defined($xmlMsg)){
932             $error_code{$fname} = NO_MSG_GIVEN;
933             $error_msg{$fname} = NO_MSG_GIVEN_MSG;
934             return undef;
935             }
936              
937             parse_xml_msg($xmlMsg);
938              
939             # Checking to see if any of these AS numbers are ones we're looking for.
940             if(scalar @as > 0){
941             foreach(@as){
942             return TRUE if defined $asNumbers{$_};
943             }
944             }
945              
946              
947              
948             # Checking to see if any of the v4 prefixes are matches.
949             if(scalar @v4 > 0){
950             foreach(@v4){
951             my $ipPrefAddr = $_;
952             my @toCheck = @{getV4comparisons($_)};
953             foreach(@toCheck){
954             my $v4Prefix = $_;
955             return TRUE if $v4Prefix->matches($ipPrefAddr);
956             }
957              
958             }
959             }
960              
961             #Checking to see if any of the v4 addresses are a match
962             if(scalar @v4 > 0){
963             foreach(@addresses){
964             my $addr = $_;
965             foreach(@v4){
966             my $tempPrefix = $_;
967             if($addr->matches($tempPrefix)){
968             return TRUE;
969             }
970             }
971              
972             }
973             }
974              
975             # Checking to see if any of the v6 addresses are matches.
976             if(scalar @v6 > 0){
977             foreach (@v6prefixes){
978             my $v6Prefix = $_;
979             #Seeing if we need to keep on to the message
980             foreach(@v6){
981             my $ipPrefAddr = $_;
982             if($v6Prefix->matches($ipPrefAddr)){
983             return TRUE;
984             }
985             }
986             }
987             }
988              
989             return FALSE;
990             }
991              
992              
993              
994              
995              
996             1;
997             __END__