File Coverage

blib/lib/Metabrik/Network/Sinfp3.pm
Criterion Covered Total %
statement 9 292 3.0
branch 0 130 0.0
condition 0 35 0.0
subroutine 3 22 13.6
pod 4 17 23.5
total 16 496 3.2


line stmt bran cond sub pod time code
1             #
2             # $Id$
3             #
4             # network::sinfp3 Brik
5             #
6             package Metabrik::Network::Sinfp3;
7 1     1   754 use strict;
  1         2  
  1         29  
8 1     1   5 use warnings;
  1         2  
  1         26  
9              
10 1     1   5 use base qw(Metabrik);
  1         2  
  1         3779  
11              
12             sub brik_properties {
13             return {
14 0     0 1   revision => '$Revision$',
15             tags => [ qw(unstable sinfp osfp fingerprint fingerprinting) ],
16             author => 'GomoR ',
17             license => 'http://opensource.org/licenses/BSD-3-Clause',
18             attributes => {
19             datadir => [ qw(datadir) ],
20             db => [ qw(sinfp3_db) ],
21             target => [ qw(target_host) ],
22             port => [ qw(tcp_port) ],
23             device => [ qw(device) ],
24             threshold => [ qw(percent) ],
25             best_score_only => [ qw(0|1) ],
26             _global => [ qw(INTERNAL) ],
27             _update_url => [ qw(INTERNAL) ],
28             },
29             attributes_default => {
30             port => 80,
31             db => 'sinfp3.db',
32             threshold => 80,
33             best_score_only => 0,
34             _update_url => 'https://www.metabrik.org/wp-content/files/sinfp/sinfp3-latest.db',
35             },
36             commands => {
37             update => [ ],
38             active_ipv4 => [ qw(target_host|OPTIONAL target_port|OPTIONAL) ],
39             active_ipv6 => [ qw(target_host|OPTIONAL target_port|OPTIONAL) ],
40             export_active_db => [ qw(sinfp3_db|OPTIONAL) ],
41             save_active_ipv4_fingerprint => [ qw(target_host|OPTIONAL target_port|OPTIONAL) ],
42             save_active_ipv6_fingerprint => [ qw(target_host|OPTIONAL target_port|OPTIONAL) ],
43             active_ipv4_from_pcap => [ qw(pcap_file) ],
44             active_ipv6_from_pcap => [ qw(pcap_file) ],
45             to_signature_from_tcp_options => [ qw(options) ],
46             to_signature_from_tcp_window_and_options => [ qw(window options) ],
47             active_ipv4_from_tcp_window_and_options => [ qw(window options) ],
48             active_ipv4_from_tcp_options => [ qw(options) ],
49             active_ipv4_from_signature => [ qw(signature) ],
50             get_os_list_from_result => [ qw(result) ],
51             },
52             require_modules => {
53             'File::Copy' => [ qw(move) ],
54             'Net::SinFP3' => [ ],
55             'Net::SinFP3::Ext::S' => [ ],
56             'Net::SinFP3::Log::Console' => [ ],
57             'Net::SinFP3::Log::Null' => [ ],
58             'Net::SinFP3::Global' => [ ],
59             'Net::SinFP3::Input::IpPort' => [ ],
60             'Net::SinFP3::Input::Pcap' => [ ],
61             'Net::SinFP3::Input::Signature' => [ ],
62             'Net::SinFP3::DB::SinFP3' => [ ],
63             'Net::SinFP3::Mode::Active' => [ ],
64             'Net::SinFP3::Search::Active' => [ ],
65             'Net::SinFP3::Search::Null' => [ ],
66             'Net::SinFP3::Output::Console' => [ ],
67             'Net::SinFP3::Output::Pcap' => [ ],
68             'Net::SinFP3::Output::Simple' => [ ],
69             'Metabrik::Client::Www' => [ ],
70             },
71             };
72             }
73              
74             sub brik_use_properties {
75 0     0 1   my $self = shift;
76              
77             return {
78 0   0       attributes_default => {
79             device => defined($self->global) && $self->global->device || 'eth0',
80             },
81             };
82             }
83              
84             sub brik_init {
85 0     0 1   my $self = shift;
86              
87 0           my $datadir = $self->datadir;
88 0           my $file = $datadir.'/'.$self->db;
89 0           my $threshold = $self->threshold;
90 0           my $best_score_only = $self->best_score_only;
91              
92 0 0         if (! -f $file) {
93 0 0         $self->update or return;
94             }
95              
96 0 0         my $log = Net::SinFP3::Log::Null->new(
97             level => $self->log->level,
98             ) or return $self->log->error('brik_init: log::null failed');
99 0           $log->init;
100              
101 0 0         my $global = Net::SinFP3::Global->new(
102             log => $log,
103             ipv6 => 0,
104             dnsReverse => 0,
105             threshold => $threshold,
106             bestScore => $best_score_only,
107             ) or return $self->log->error('brik_init: global failed');
108              
109 0 0         my $db = Net::SinFP3::DB::SinFP3->new(
110             global => $global,
111             file => $file,
112             ) or return $self->log->error('brik_init: db::sinfp3 failed');
113 0           $db->init;
114 0           $global->db($db);
115              
116 0           $self->_global($global);
117              
118 0           return $self->SUPER::brik_init(@_);
119             }
120              
121             sub update {
122 0     0 0   my $self = shift;
123              
124 0           my $db = $self->db;
125 0           my $datadir = $self->datadir;
126              
127 0           my $url = $self->_update_url;
128              
129 0 0         my $cw = Metabrik::Client::Www->new_from_brik_init($self) or return;
130 0 0         my $files = $cw->mirror($url, $db, $datadir) or return;
131 0 0         if (@$files > 0) {
132 0           $self->log->info("update: $db updated");
133             }
134              
135 0           return "$datadir/$db";
136             }
137              
138             sub active_ipv4 {
139 0     0 0   my $self = shift;
140 0           my ($target, $port) = @_;
141              
142 0   0       $target ||= $self->target;
143 0   0       $port ||= $self->port;
144 0 0         $self->brik_help_run_must_be_root('active_ipv4') or return;
145 0 0         $self->brik_help_run_undef_arg('active_ipv4', $target) or return;
146 0 0         $self->brik_help_run_undef_arg('active_ipv4', $port) or return;
147              
148 0           my $device = $self->device;
149 0           my $threshold = $self->threshold;
150              
151 0           my $datadir = $self->datadir;
152 0           my $file = $datadir.'/'.$self->db;
153 0 0         $self->brik_help_run_file_not_found('active_ipv4', $file) or return;
154              
155 0           my $log = Net::SinFP3::Log::Console->new(
156             level => $self->log->level,
157             );
158              
159 0 0         my $global = Net::SinFP3::Global->new(
160             log => $log,
161             target => $target,
162             port => $port,
163             ipv6 => 0,
164             dnsReverse => 0,
165             worker => 'single',
166             device => $device,
167             threshold => $threshold,
168             ) or return $self->log->error("active: global failed");
169              
170 0           my $input = Net::SinFP3::Input::IpPort->new(
171             global => $global,
172             );
173              
174 0           my $db = Net::SinFP3::DB::SinFP3->new(
175             global => $global,
176             file => $file,
177             );
178              
179 0           my $mode = Net::SinFP3::Mode::Active->new(
180             global => $global,
181             doP1 => 1,
182             doP2 => 1,
183             doP3 => 1,
184             );
185              
186 0           my $search = Net::SinFP3::Search::Active->new(
187             global => $global,
188             );
189              
190 0           my $output = Net::SinFP3::Output::Simple->new(
191             global => $global,
192             );
193              
194 0           my $sinfp3 = Net::SinFP3->new(
195             global => $global,
196             input => [ $input ],
197             db => [ $db ],
198             mode => [ $mode ],
199             search => [ $search ],
200             output => [ $output ],
201             );
202              
203 0           my $ret = $sinfp3->run;
204              
205 0           my @result = $global->result;
206              
207 0           $db->post;
208 0           $log->post;
209              
210 0           return \@result;
211              
212             # I was quite mad at this time.
213             #$global->mode($mode);
214             #$mode->init;
215             #$mode->run;
216             #$db->init;
217             #$db->run;
218             #$global->db($db);
219             #$global->search($search);
220             #$search->init;
221             #my $result = $search->run;
222              
223             #return $result;
224             }
225              
226             sub export_active_db {
227 0     0 0   my $self = shift;
228 0           my ($db) = @_;
229              
230 0   0       $db ||= $self->db;
231 0 0         $self->brik_help_run_undef_arg('export_active_db', $db) or return;
232 0 0         $self->brik_help_run_file_not_found('export_active_db', $db) or return;
233              
234 0           return 1;
235             }
236              
237             sub save_active_ipv4_fingerprint {
238 0     0 0   my $self = shift;
239 0           my ($target_host, $target_port) = @_;
240              
241 0   0       $target_host ||= $self->target;
242 0   0       $target_port ||= $self->port;
243 0           my $device = $self->device;
244 0 0         $self->brik_help_run_undef_arg('save_active_ipv4_fingerprint', $target_host) or return;
245 0 0         $self->brik_help_run_undef_arg('save_active_ipv4_fingerprint', $target_port) or return;
246              
247 0           my $datadir = $self->datadir;
248 0           my $file = $datadir.'/'.$self->db;
249 0 0         $self->brik_help_run_file_not_found('save_active_ipv4_fingerprint', $file) or return;
250              
251 0           my $threshold = $self->threshold;
252              
253 0           my $log = Net::SinFP3::Log::Console->new(
254             level => $self->log->level,
255             );
256              
257 0 0         my $global = Net::SinFP3::Global->new(
258             log => $log,
259             target => $target_host,
260             port => $target_port,
261             ipv6 => 0,
262             dnsReverse => 0,
263             device => $device,
264             threshold => $threshold,
265             ) or return $self->log->error("save_active_ipv4_fingerprint: global failed");
266              
267 0           my $input = Net::SinFP3::Input::IpPort->new(
268             global => $global,
269             );
270              
271 0           my $db = Net::SinFP3::DB::SinFP3->new(
272             global => $global,
273             );
274              
275 0           my $mode = Net::SinFP3::Mode::Active->new(
276             global => $global,
277             doP1 => 1,
278             doP2 => 1,
279             doP3 => 1,
280             );
281              
282 0           my $search = Net::SinFP3::Search::Active->new(
283             global => $global,
284             );
285              
286 0           my $output = Net::SinFP3::Output::Pcap->new(
287             global => $global,
288             anonymize => 1,
289             );
290              
291 0           my $sinfp3 = Net::SinFP3->new(
292             global => $global,
293             input => [ $input ],
294             db => [ $db ],
295             mode => [ $mode ],
296             search => [ $search ],
297             output => [ $output ],
298             );
299              
300 0           my $ret = $sinfp3->run;
301              
302 0           $log->post;
303              
304 0           my $pcap = 'sinfp4-127.0.0.1-'.$target_port.'.pcap';
305 0 0         if (-f $pcap) {
306 0           File::Copy::move($pcap, $datadir);
307             }
308              
309 0           return $datadir."/$pcap";
310             }
311              
312             sub save_active_ipv6_fingerprint {
313 0     0 0   my $self = shift;
314 0           my ($target_host, $target_port) = @_;
315              
316 0   0       $target_host ||= $self->target;
317 0   0       $target_port ||= $self->port;
318 0           my $device = $self->device;
319 0 0         $self->brik_help_run_undef_arg('save_active_ipv6_fingerprint', $target_host) or return;
320 0 0         $self->brik_help_run_undef_arg('save_active_ipv6_fingerprint', $target_port) or return;
321              
322 0           my $datadir = $self->datadir;
323 0           my $file = $datadir.'/'.$self->db;
324 0 0         $self->brik_help_run_file_not_found('save_active_ipv6_fingerprint', $file) or return;
325              
326 0           my $threshold = $self->threshold;
327              
328 0           my $log = Net::SinFP3::Log::Console->new(
329             level => $self->log->level,
330             );
331              
332 0 0         my $global = Net::SinFP3::Global->new(
333             log => $log,
334             target => $target_host,
335             port => $target_port,
336             ipv6 => 1,
337             dnsReverse => 0,
338             device => $device,
339             threshold => $threshold,
340             ) or return $self->log->error("save_active_ipv6_fingerprint: global failed");
341              
342 0           my $input = Net::SinFP3::Input::IpPort->new(
343             global => $global,
344             );
345              
346 0           my $db = Net::SinFP3::DB::SinFP3->new(
347             global => $global,
348             file => $file,
349             );
350              
351 0           my $mode = Net::SinFP3::Mode::Active->new(
352             global => $global,
353             doP1 => 1,
354             doP2 => 1,
355             doP3 => 1,
356             );
357              
358 0           my $search = Net::SinFP3::Search::Active->new(
359             global => $global,
360             );
361              
362 0           my $output = Net::SinFP3::Output::Pcap->new(
363             global => $global,
364             anonymize => 1,
365             );
366              
367 0           my $sinfp3 = Net::SinFP3->new(
368             global => $global,
369             input => [ $input ],
370             db => [ $db ],
371             mode => [ $mode ],
372             search => [ $search ],
373             output => [ $output ],
374             );
375              
376 0           my $ret = $sinfp3->run;
377              
378 0           $log->post;
379              
380 0           my $pcap = 'sinfp6-::1-'.$target_port.'.pcap';
381 0 0         if (-f $pcap) {
382 0           File::Copy::move($pcap, $datadir);
383             }
384              
385 0           return $datadir."/$pcap";
386             }
387              
388             sub active_ipv4_from_pcap {
389 0     0 0   my $self = shift;
390 0           my ($pcap_file) = @_;
391              
392 0           my $device = $self->device;
393 0 0         $self->brik_help_run_undef_arg('active_ipv4_from_pcap', $pcap_file) or return;
394 0 0         $self->brik_help_run_file_not_found('active_ipv4_from_pcap', $pcap_file) or return;
395              
396 0           my $datadir = $self->datadir;
397 0           my $file = $datadir.'/'.$self->db;
398 0 0         $self->brik_help_run_file_not_found('active_ipv4_from_pcap', $file) or return;
399              
400 0           my $threshold = $self->threshold;
401              
402 0           my $log = Net::SinFP3::Log::Console->new(
403             level => $self->log->level,
404             );
405              
406 0 0         my $global = Net::SinFP3::Global->new(
407             log => $log,
408             ipv6 => 0,
409             dnsReverse => 0,
410             device => $device,
411             threshold => $threshold,
412             ) or return $self->log->error("active_ipv4_from_pcap: global failed");
413              
414 0           my $input = Net::SinFP3::Input::Pcap->new(
415             global => $global,
416             file => $pcap_file,
417             count => 10,
418             );
419              
420 0           my $db = Net::SinFP3::DB::SinFP3->new(
421             global => $global,
422             file => $file,
423             );
424              
425 0           my $mode = Net::SinFP3::Mode::Active->new(
426             global => $global,
427             doP1 => 1,
428             doP2 => 1,
429             doP3 => 1,
430             );
431              
432 0           my $search = Net::SinFP3::Search::Active->new(
433             global => $global,
434             );
435              
436 0           my $output = Net::SinFP3::Output::Console->new(
437             global => $global,
438             );
439              
440 0           my $sinfp3 = Net::SinFP3->new(
441             global => $global,
442             input => [ $input ],
443             db => [ $db ],
444             mode => [ $mode ],
445             search => [ $search ],
446             output => [ $output ],
447             );
448              
449 0           my $ret = $sinfp3->run;
450              
451 0           $log->post;
452              
453 0           return $ret;
454             }
455              
456             sub active_ipv6_from_pcap {
457 0     0 0   my $self = shift;
458 0           my ($pcap_file) = @_;
459              
460 0           my $device = $self->device;
461 0 0         $self->brik_help_run_undef_arg('active_ipv6_from_pcap', $pcap_file) or return;
462 0 0         $self->brik_help_run_file_not_found('active_ipv6_from_pcap', $pcap_file) or return;
463              
464 0           my $datadir = $self->datadir;
465 0           my $file = $datadir.'/'.$self->db;
466 0 0         $self->brik_help_run_file_not_found('active_ipv6_from_pcap', $file) or return;
467              
468 0           my $threshold = $self->threshold;
469              
470 0           my $log = Net::SinFP3::Log::Console->new(
471             level => $self->log->level,
472             );
473              
474 0 0         my $global = Net::SinFP3::Global->new(
475             log => $log,
476             ipv6 => 1,
477             dnsReverse => 0,
478             device => $device,
479             threshold => $threshold,
480             ) or return $self->log->error("active_ipv6_from_pcap: global failed");
481              
482 0           my $input = Net::SinFP3::Input::Pcap->new(
483             global => $global,
484             file => $pcap_file,
485             count => 10,
486             );
487              
488 0           my $db = Net::SinFP3::DB::SinFP3->new(
489             global => $global,
490             file => $file,
491             );
492              
493 0           my $mode = Net::SinFP3::Mode::Active->new(
494             global => $global,
495             doP1 => 1,
496             doP2 => 1,
497             doP3 => 1,
498             );
499              
500 0           my $search = Net::SinFP3::Search::Active->new(
501             global => $global,
502             );
503              
504 0           my $output = Net::SinFP3::Output::Console->new(
505             global => $global,
506             );
507              
508 0           my $sinfp3 = Net::SinFP3->new(
509             global => $global,
510             input => [ $input ],
511             db => [ $db ],
512             mode => [ $mode ],
513             search => [ $search ],
514             output => [ $output ],
515             );
516              
517 0           my $ret = $sinfp3->run;
518              
519 0           $log->post;
520              
521 0           return $ret;
522             }
523              
524             sub _parse_result {
525 0     0     my $self = shift;
526 0           my ($result) = @_;
527              
528 0           my @final = ();
529 0           for my $r (@$result) {
530 0           my $h = {
531             id_signature => $r->idSignature,
532             ip_version => $r->ipVersion,
533             system_class => $r->systemClass,
534             vendor => $r->vendor,
535             os => $r->os,
536             os_version => $r->osVersion,
537             os_version_family => $r->osVersionFamily,
538             match_type => $r->matchType,
539             match_score => $r->matchScore,
540             match_mask => $r->matchMask,
541             };
542 0           for ($r->osVersionChildrenList) {
543 0           push @{$h->{os_version_children}}, $_;
  0            
544             }
545 0           push @final, $h;
546             }
547              
548 0           return \@final;
549             }
550              
551             sub _analyze_options {
552 0     0     my $self = shift;
553 0           my ($opts) = @_;
554              
555             # Rewrite timestamp values, if > 0 overwrite with ffff,
556             # for each timestamp. Same with WScale value
557 0           my $mss;
558             my $wscale;
559 0 0         if ($opts =~ m/^(.*080a)(.{8})(.{8})(.*)/) {
560 0           my $head = $1;
561 0           my $a = $2;
562 0           my $b = $3;
563 0           my $tail = $4;
564             # Some systems put timestamp values to 00. We keep it for
565             # fingerprint matching. If there is no DEAD, it is not a
566             # reply to a SinFP3 probe, we strip this value.
567 0 0 0       if ($a !~ /00000000/ && $a !~ /44454144/) {
568 0           $a = "........";
569             }
570 0 0 0       if ($b !~ /00000000/ && $b !~ /44454144/) {
571 0           $b = "........";
572             }
573 0           $opts = $head.$a.$b.$tail;
574             }
575             # Move MSS value in its own field
576 0 0         if ($opts =~ /0204(....)/) {
577 0 0         if ($1) {
578 0           $mss = sprintf("%d", hex($1));
579 0           $opts =~ s/0204..../0204ffff/;
580             }
581             }
582             # Move WScale value in its own field
583 0 0         if ($opts =~ /0303(..)/) {
584 0 0         if ($1) {
585 0           $wscale = sprintf("%d", hex($1));
586 0           $opts =~ s/0303../0303ff/;
587             }
588             }
589              
590             # We completely ignore payload from original SinFP3 code.
591             # If we want it, we have to pad $opts with it.
592             #$opts .= unpack('H*', $p->reply->ref->{TCP}->payload)
593             #if $p->reply->ref->{TCP}->payload;
594              
595 0   0       $opts ||= '0';
596 0   0       $mss ||= '0';
597 0   0       $wscale ||= '0';
598              
599 0 0         my $opt_len = $opts ? length($opts) / 2 : 0;
600              
601 0           return [ $opts, $mss, $wscale, $opt_len ];
602             }
603              
604             sub to_signature_from_tcp_window_and_options {
605 0     0 0   my $self = shift;
606 0           my ($window, $options) = @_;
607              
608 0 0         $self->brik_help_run_undef_arg('to_signature_from_tcp_window_and_options', $window)
609             or return;
610 0 0         $self->brik_help_run_undef_arg('to_signature_from_tcp_window_and_options', $options)
611             or return;
612              
613             #
614             # Example:
615             # S2: B11113 F0x12 W65535 O0204ffff010303ff0402080affffffff44454144 M1460 S6 L20
616             #
617             # Convert TCP options, extract MSS and Scale values
618 0           my $a = $self->_analyze_options($options);
619 0           my $tcp_options = $a->[0];
620 0           my $tcp_mss = $a->[1];
621 0           my $tcp_scale = $a->[2];
622 0           my $opt_len = $a->[3];
623              
624             return {
625 0           B => '.....', # We completly ignore IP header.
626             F => '0x12', # We consider it is a SYN|ACK
627             W => $window,
628             O => $tcp_options,
629             M => $tcp_mss,
630             S => $tcp_scale,
631             L => $opt_len,
632             };
633             }
634              
635             sub to_signature_from_tcp_options {
636 0     0 0   my $self = shift;
637 0           my ($options) = @_;
638              
639 0 0         $self->brik_help_run_undef_arg('to_signature_from_tcp_options', $options) or return;
640              
641             #
642             # Example:
643             # S2: B11113 F0x12 W65535 O0204ffff010303ff0402080affffffff44454144 M1460 S6 L20
644             #
645             # Convert TCP options, extract MSS and Scale values
646 0           my $a = $self->_analyze_options($options);
647 0           my $tcp_options = $a->[0];
648 0           my $tcp_mss = $a->[1];
649 0           my $tcp_scale = $a->[2];
650 0           my $opt_len = $a->[3];
651              
652             return {
653 0           B => '.....', # We completely ignore IP header.
654             F => '0x12', # We consider it is a SYN|ACK
655             W => '\\d+', # We completely ignore TCP window size.
656             O => $tcp_options,
657             M => $tcp_mss,
658             S => $tcp_scale,
659             L => $opt_len,
660             };
661             }
662              
663             sub active_ipv4_from_tcp_window_and_options {
664 0     0 0   my $self = shift;
665 0           my ($window, $options) = @_;
666              
667 0 0         $self->brik_help_run_undef_arg('active_ipv4_from_tcp_window_and_options', $window)
668             or return;
669 0 0         $self->brik_help_run_undef_arg('active_ipv4_from_tcp_window_and_options', $options)
670             or return;
671              
672 0           my $global = $self->_global;
673              
674 0 0         my $mode = Net::SinFP3::Mode::Active->new(
675             global => $global,
676             doP1 => 1,
677             doP2 => 1,
678             doP3 => 1,
679             ) or return $self->log->error('active_ipv4_from_tcp_window_and_options: mode::active failed');
680 0           $mode->init;
681 0           $global->mode($mode);
682              
683 0 0         my $s = $self->to_signature_from_tcp_window_and_options($window, $options) or return;
684             my $s2 = Net::SinFP3::Ext::S->new(
685             B => 'B'.$s->{B},
686             F => 'F'.$s->{F},
687             W => 'W'.$s->{W},
688             O => 'O'.$s->{O},
689             M => 'M'.$s->{M},
690             S => 'S'.$s->{S},
691             L => 'L'.$s->{L},
692 0           );
693 0 0         if (! defined($s2)) {
694 0           return $self->log->error('active_ipv4_from_tcp_window_and_options: ext::s failed');
695             }
696              
697 0           my $search = Net::SinFP3::Search::Active->new(
698             global => $global,
699             #s1 => $s1,
700             s2 => $s2, # We only use S2 here. Be sure to have enough TCP options in your reply.
701             #s3 => $s3,
702             );
703 0           $search->init;
704 0           $global->search($search);
705              
706 0           my $r = $search->search;
707              
708 0           return $self->_parse_result($r);
709             }
710              
711             sub active_ipv4_from_tcp_options {
712 0     0 0   my $self = shift;
713 0           my ($options) = @_;
714              
715 0 0         $self->brik_help_run_undef_arg('active_ipv4_from_tcp_options', $options) or return;
716              
717 0           my $global = $self->_global;
718              
719 0 0         my $mode = Net::SinFP3::Mode::Active->new(
720             global => $global,
721             doP1 => 1,
722             doP2 => 1,
723             doP3 => 1,
724             ) or return $self->log->error('active_ipv4_from_tcp_options: mode::active failed');
725 0           $mode->init;
726 0           $global->mode($mode);
727              
728 0 0         my $s = $self->to_signature_from_tcp_options($options) or return;
729             my $s2 = Net::SinFP3::Ext::S->new(
730             B => 'B'.$s->{B},
731             F => 'F'.$s->{F},
732             W => 'W'.$s->{W},
733             O => 'O'.$s->{O},
734             M => 'M'.$s->{M},
735             S => 'S'.$s->{S},
736             L => 'L'.$s->{L},
737 0           );
738 0 0         if (! defined($s2)) {
739 0           return $self->log->error('active_ipv4_from_tcp_options: ext::s failed');
740             }
741              
742 0           my $search = Net::SinFP3::Search::Active->new(
743             global => $global,
744             #s1 => $s1,
745             s2 => $s2, # We only use S2 here. Be sure to have enough TCP options in your reply.
746             #s3 => $s3,
747             );
748 0           $search->init;
749 0           $global->search($search);
750              
751 0           my $r = $search->search;
752              
753 0           return $self->_parse_result($r);
754             }
755              
756             sub active_ipv4_from_signature {
757 0     0 0   my $self = shift;
758 0           my ($signature) = @_;
759              
760 0 0         $self->brik_help_run_undef_arg('active_ipv4_from_signature', $signature) or return;
761 0 0         $self->brik_help_run_invalid_arg('active_ipv4_from_signature', $signature, 'HASH') or return;
762              
763 0           my $global = $self->_global;
764              
765 0 0         my $mode = Net::SinFP3::Mode::Active->new(
766             global => $global,
767             doP1 => 1,
768             doP2 => 1,
769             doP3 => 1,
770             ) or return $self->log->error('active_ipv4_from_signature: mode::active failed');
771 0           $mode->init;
772 0           $global->mode($mode);
773              
774             my $s2 = Net::SinFP3::Ext::S->new(
775             B => 'B'.$signature->{B},
776             F => 'F'.$signature->{F},
777             W => 'W'.$signature->{W},
778             O => 'O'.$signature->{O},
779             M => 'M'.$signature->{M},
780             S => 'S'.$signature->{S},
781             L => 'L'.$signature->{L},
782 0           );
783 0 0         if (! defined($s2)) {
784 0           return $self->log->error('active_ipv4_from_signature: ext::s failed');
785             }
786              
787 0           my $search = Net::SinFP3::Search::Active->new(
788             global => $global,
789             #s1 => $s1,
790             s2 => $s2, # We only use S2 here. Be sure to have enough TCP options in your reply.
791             #s3 => $s3,
792             );
793 0           $search->init;
794 0           $global->search($search);
795              
796 0           my $r = $search->search;
797              
798 0           return $self->_parse_result($r);
799             }
800              
801             sub get_os_list_from_result {
802 0     0 0   my $self = shift;
803 0           my ($result) = @_;
804              
805 0 0         $self->brik_help_run_undef_arg('get_os_list_from_result', $result) or return;
806 0 0         $self->brik_help_run_invalid_arg('get_os_list_from_result', $result, 'ARRAY') or return;
807 0 0         $self->brik_help_run_empty_array_arg('get_os_list_from_result', $result) or return;
808              
809 0           my %os_list = map { $_->{os} => 1 } @$result;
  0            
810              
811 0           return [ sort { $a cmp $b } keys %os_list ];
  0            
812             }
813              
814             sub brik_fini {
815 0     0 1   my $self = shift;
816              
817 0           my $global = $self->_global;
818 0 0         if (defined($global)) {
819 0           my $search = $global->search;
820 0           my $mode = $global->mode;
821 0           my $db = $global->db;
822 0           my $log = $global->log;
823              
824 0 0         if (defined($search)) {
825 0           $search->post;
826             }
827 0 0         if (defined($mode)) {
828 0           $mode->post;
829             }
830 0 0         if (defined($db)) {
831 0           $db->post;
832             }
833 0 0         if (defined($log)) {
834 0           $log->post;
835             }
836 0           $global->search(undef);
837 0           $global->mode(undef);
838 0           $global->db(undef);
839 0           $global->log(undef);
840 0           $self->_global(undef);
841              
842 0           return 1;
843             }
844              
845 0           return 0;
846             }
847              
848             1;
849              
850             __END__