File Coverage

blib/lib/Metabrik/Network/Portscan.pm
Criterion Covered Total %
statement 9 207 4.3
branch 0 150 0.0
condition 0 62 0.0
subroutine 3 13 23.0
pod 2 10 20.0
total 14 442 3.1


line stmt bran cond sub pod time code
1             #
2             # $Id$
3             #
4             # network::portscan Brik
5             #
6             package Metabrik::Network::Portscan;
7 1     1   796 use strict;
  1         3  
  1         28  
8 1     1   5 use warnings;
  1         2  
  1         25  
9              
10 1     1   5 use base qw(Metabrik::Network::Device);
  1         2  
  1         3203  
11              
12             sub brik_properties {
13             return {
14 0     0 1   revision => '$Revision$',
15             tags => [ qw(unstable scan syn port synscan tcpscan) ],
16             author => 'GomoR ',
17             license => 'http://opensource.org/licenses/BSD-3-Clause',
18             attributes => {
19             device => [ qw(device) ],
20             listen_device => [ qw(device) ],
21             ports => [ qw(port_array) ],
22             top10 => [ qw(top10_port_array) ],
23             top100 => [ qw(top100_port_array) ],
24             top1000 => [ qw(top1000_port_array) ],
25             pps => [ qw(pps) ],
26             try => [ qw(try) ],
27             bandwidth => [ qw(bandwidth) ],
28             wait => [ qw(seconds) ],
29             use_ipv6 => [ qw(0|1) ],
30             src_ip => [ qw(ip_address) ],
31             filter_code_optimizer => [ qw(0|1) ],
32             _nr => [ qw(INTERNAL) ],
33             },
34             attributes_default => {
35             top10 => [ qw(
36             21 22 23 25 80 135 139 443 445 3389
37             ) ],
38             top100 => [ qw(
39             7 9 13 21 22 23 25 26 37 53 79 80 81 88 106 110 111 113
40             119 135 139 143 144 179 199 389 427 443 444 445 465 513 514
41             515 543 544 548 554 587 631 646 873 990 993 995 1025 1026 1027
42             1028 1029 1110 1433 1720 1723 1755 1900 2000 2001 2049 2121 2717
43             3000 3128 3306 3389 3986 4899 5000 5009 5051 5060 5101 5190 5357
44             5432 5631 5666 5800 5900 6000 6001 6646 7070 8000 8008 8009 8080
45             8081 8443 8888 9100 9999 10000 32768 49152 49153 49154 49155
46             49156 49157
47             ) ],
48             top1000 => [ qw(
49             1 3 4 6 7 9 13 17 19 20 21 22 23 24 25 26 30 32 33 37
50             42 43 49 53 70 79 80 81 82 83 84 85 88 89 90 99 100 106
51             109 110 111 113 119 125 135 139 143 144 146 161 163 179 199
52             211 212 222 254 255 256 259 264 280 301 306 311 340 366 389
53             406 407 416 417 425 427 443 444 445 458 464 465 481 497 500
54             512 513 514 515 524 541 543 544 545 548 554 555 563 587 593
55             616 617 625 631 636 646 648 666 667 668 683 687 691 700 705
56             711 714 720 722 726 749 765 777 783 787 800 801 808 843 873
57             880 888 898 900 901 902 903 911 912 981 987 990 992 993 995
58             999 1000 1001 1002 1007 1009 1010 1011 1021 1022 1023 1024 1025
59             1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038
60             1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051
61             1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064
62             1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077
63             1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090
64             1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1102 1104 1105
65             1106 1107 1108 1110 1111 1112 1113 1114 1117 1119 1121 1122 1123
66             1124 1126 1130 1131 1132 1137 1138 1141 1145 1147 1148 1149 1151
67             1152 1154 1163 1164 1165 1166 1169 1174 1175 1183 1185 1186 1187
68             1192 1198 1199 1201 1213 1216 1217 1218 1233 1234 1236 1244 1247
69             1248 1259 1271 1272 1277 1287 1296 1300 1301 1309 1310 1311 1322
70             1328 1334 1352 1417 1433 1434 1443 1455 1461 1494 1500 1501 1503
71             1521 1524 1533 1556 1580 1583 1594 1600 1641 1658 1666 1687 1688
72             1700 1717 1718 1719 1720 1721 1723 1755 1761 1782 1783 1801 1805
73             1812 1839 1840 1862 1863 1864 1875 1900 1914 1935 1947 1971 1972
74             1974 1984 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008
75             2009 2010 2013 2020 2021 2022 2030 2033 2034 2035 2038 2040 2041
76             2042 2043 2045 2046 2047 2048 2049 2065 2068 2099 2100 2103 2105
77             2106 2107 2111 2119 2121 2126 2135 2144 2160 2161 2170 2179 2190
78             2191 2196 2200 2222 2251 2260 2288 2301 2323 2366 2381 2382 2383
79             2393 2394 2399 2401 2492 2500 2522 2525 2557 2601 2602 2604 2605
80             2607 2608 2638 2701 2702 2710 2717 2718 2725 2800 2809 2811 2869
81             2875 2909 2910 2920 2967 2968 2998 3000 3001 3003 3005 3006 3007
82             3011 3013 3017 3030 3031 3050 3052 3071 3077 3128 3168 3211 3221
83             3260 3261 3268 3269 3283 3300 3301 3306 3322 3323 3324 3325 3333
84             3351 3367 3369 3370 3371 3372 3389 3390 3404 3476 3493 3517 3527
85             3546 3551 3580 3659 3689 3690 3703 3737 3766 3784 3800 3801 3809
86             3814 3826 3827 3828 3851 3869 3871 3878 3880 3889 3905 3914 3918
87             3920 3945 3971 3986 3995 3998 4000 4001 4002 4003 4004 4005 4006
88             4045 4111 4125 4126 4129 4224 4242 4279 4321 4343 4443 4444 4445
89             4446 4449 4550 4567 4662 4848 4899 4900 4998 5000 5001 5002 5003
90             5004 5009 5030 5033 5050 5051 5054 5060 5061 5080 5087 5100 5101
91             5102 5120 5190 5200 5214 5221 5222 5225 5226 5269 5280 5298 5357
92             5405 5414 5431 5432 5440 5500 5510 5544 5550 5555 5560 5566 5631
93             5633 5666 5678 5679 5718 5730 5800 5801 5802 5810 5811 5815 5822
94             5825 5850 5859 5862 5877 5900 5901 5902 5903 5904 5906 5907 5910
95             5911 5915 5922 5925 5950 5952 5959 5960 5961 5962 5963 5987 5988
96             5989 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6009 6025
97             6059 6100 6101 6106 6112 6123 6129 6156 6346 6389 6502 6510 6543
98             6547 6565 6566 6567 6580 6646 6666 6667 6668 6669 6689 6692 6699
99             6779 6788 6789 6792 6839 6881 6901 6969 7000 7001 7002 7004 7007
100             7019 7025 7070 7100 7103 7106 7200 7201 7402 7435 7443 7496 7512
101             7625 7627 7676 7741 7777 7778 7800 7911 7920 7921 7937 7938 7999
102             8000 8001 8002 8007 8008 8009 8010 8011 8021 8022 8031 8042 8045
103             8080 8081 8082 8083 8084 8085 8086 8087 8088 8089 8090 8093 8099
104             8100 8180 8181 8192 8193 8194 8200 8222 8254 8290 8291 8292 8300
105             8333 8383 8400 8402 8443 8500 8600 8649 8651 8652 8654 8701 8800
106             8873 8888 8899 8994 9000 9001 9002 9003 9009 9010 9011 9040 9050
107             9071 9080 9081 9090 9091 9099 9100 9101 9102 9103 9110 9111 9200
108             9207 9220 9290 9415 9418 9485 9500 9502 9503 9535 9575 9593 9594
109             9595 9618 9666 9876 9877 9878 9898 9900 9917 9943 9944 9968 9998
110             9999 10000 10001 10002 10003 10004 10009 10010 10012 10024 10025
111             10082 10180 10215 10243 10566 10616 10617 10621 10626 10628 10629
112             10778 11110 11111 11967 12000 12174 12265 12345 13456 13722 13782
113             13783 14000 14238 14441 14442 15000 15002 15003 15004 15660 15742
114             16000 16001 16012 16016 16018 16080 16113 16992 16993 17877 17988
115             18040 18101 18988 19101 19283 19315 19350 19780 19801 19842 20000
116             20005 20031 20221 20222 20828 21571 22939 23502 24444 24800 25734
117             25735 26214 27000 27352 27353 27355 27356 27715 28201 30000 30718
118             30951 31038 31337 32768 32769 32770 32771 32772 32773 32774 32775
119             32776 32777 32778 32779 32780 32781 32782 32783 32784 32785 33354
120             33899 34571 34572 34573 35500 38292 40193 40911 41511 42510 44176
121             44442 44443 44501 45100 48080 49152 49153 49154 49155 49156 49157
122             49158 49159 49160 49161 49163 49165 49167 49175 49176 49400 49999
123             50000 50001 50002 50003 50006 50300 50389 50500 50636 50800 51103
124             51493 52673 52822 52848 52869 54045 54328 55055 55056 55555 55600
125             56737 56738 57294 57797 58080 60020 60443 61532 61900 62078 63331
126             64623 64680 65000 65129 65389
127             ) ],
128             pps => 10_000,
129             try => 2,
130             wait => 5, # Wait 5 seconds for last packet
131             use_ipv6 => 0,
132             filter_code_optimizer => 0,
133             },
134             commands => {
135             estimate_runtime => [ qw($ip_list $port_list|OPTIONAL pps|OPTIONAL try|OPTIONAL) ],
136             estimate_bandwidth => [ qw(pps|OPTIONAL size|OPTIONAL) ],
137             estimate_pps => [ qw(bandwidth|OPTIONAL size|OPTIONAL) ],
138             tcp_syn_sender => [ qw($ip_list $port_list|OPTIONAL pps|OPTIONAL try|OPTIONAL) ],
139             tcp_syn_start_receiver => [ qw($port_list|OPTIONAL filter|OPTIONAL listen_device|OPTIONAL) ],
140             tcp_syn_stop_receiver => [ ],
141             tcp_syn_scan => [ qw($ip_list $port_list|OPTIONAL pps|OPTIONAL try|OPTIONAL) ],
142             tcp_syn_receive_until_sender_exit => [ qw(pid pps|OPTIONAL wait|OPTIONAL use_ipv6|OPTIONAL) ],
143             },
144             require_modules => {
145             'Net::Write::Fast' => [ ],
146             'Net::Frame::Simple' => [ ],
147             'POSIX' => [ qw(ceil) ],
148             'Metabrik::Network::Address' => [ ],
149             'Metabrik::Network::Read' => [ ],
150             'Metabrik::System::Process' => [ ],
151             'Metabrik::Worker::Fork' => [ ],
152             },
153             };
154             }
155              
156             sub brik_use_properties {
157 0     0 1   my $self = shift;
158              
159             return {
160 0   0       attributes_default => {
      0        
161             device => defined($self->global) && $self->global->device || 'eth0',
162             listen_device => defined($self->global) && $self->global->device || 'eth0',
163             },
164             };
165             }
166              
167             sub estimate_runtime {
168 0     0 0   my $self = shift;
169 0           my ($ip_list, $port_list, $pps, $try) = @_;
170              
171 0   0       $port_list ||= $self->ports || $self->top100;
      0        
172 0   0       $pps ||= $self->pps;
173 0   0       $try ||= $self->try;
174 0 0         $self->brik_help_run_undef_arg('estimate_runtime', $ip_list) or return;
175 0 0         $self->brik_help_run_undef_arg('estimate_runtime', $port_list) or return;
176              
177 0 0         my $runtime = Net::Write::Fast::estimate_runtime({
178             targets => $ip_list,
179             ports => $port_list,
180             pps => $pps,
181             try => $try,
182             }) or return $self->log->error('estimate_runtime: failed');
183              
184 0           return $runtime;
185             }
186              
187              
188             sub estimate_bandwidth {
189 0     0 0   my $self = shift;
190 0           my ($pps, $size) = @_;
191              
192 0   0       $pps ||= $self->pps;
193             #$size ||= 74; # Ethernet (14) + IP (20), + TCP (20) + TCP options (20)
194 0   0       $size ||= 60; # IP (20), + TCP (20) + TCP options (20)
195              
196 0           my $count = $pps * $size;
197              
198 0 0         if (length($pps) > 8) {
    0          
    0          
199 0           $count /= 1_000_000_000;
200 0           return "${count}G";
201             }
202             elsif (length($pps) > 5) {
203 0           $count /= 1_000_000;
204 0           return "${count}M";
205             }
206             elsif (length($pps) > 2) {
207 0           $count /= 1_000;
208 0           return "${count}K";
209             }
210              
211 0           return "${count}B";
212             }
213              
214             sub estimate_pps {
215 0     0 0   my $self = shift;
216 0           my ($bandwidth, $size) = @_;
217              
218 0   0       $bandwidth ||= $self->bandwidth;
219             #$size ||= 74; # Ethernet (14) + IP (20), + TCP (20) + TCP options (20)
220 0   0       $size ||= 60; # IP (20), + TCP (20) + TCP options (20)
221              
222 0           my $count = 0;
223 0 0         if ($bandwidth =~ m{B$}) {
    0          
    0          
    0          
224 0           $bandwidth =~ s/.$//;
225 0           $count = $bandwidth;
226             }
227             elsif ($bandwidth =~ m{K$}) {
228 0           $bandwidth =~ s/.$//;
229 0           $count = $bandwidth * 1_000;
230             }
231             elsif ($bandwidth =~ m{M$}) {
232 0           $bandwidth =~ s/.$//;
233 0           $count = $bandwidth * 1_000_000;
234             }
235             elsif ($bandwidth =~ m{G$}) {
236 0           $bandwidth =~ s/.$//;
237 0           $count = $bandwidth * 1_000_000_000;
238             }
239              
240 0           return $count / $size;
241             }
242              
243             sub tcp_syn_sender {
244 0     0 0   my $self = shift;
245 0           my ($ip_list, $port_list, $pps, $try) = @_;
246              
247 0   0       $port_list ||= $self->ports || $self->top100;
      0        
248 0   0       $pps ||= $self->pps;
249 0   0       $try ||= $self->try;
250 0 0         $self->brik_help_run_undef_arg('tcp_syn_sender', $ip_list) or return;
251 0 0         $self->brik_help_run_invalid_arg('tcp_syn_sender', $ip_list, 'ARRAY') or return;
252 0 0         $self->brik_help_run_empty_array_arg('tcp_syn_sender', $ip_list, 'ARRAY') or return;
253 0 0         $self->brik_help_run_undef_arg('tcp_syn_sender', $port_list) or return;
254 0 0         $self->brik_help_run_invalid_arg('tcp_syn_sender', $port_list, 'ARRAY') or return;
255 0 0         $self->brik_help_run_empty_array_arg('tcp_syn_sender', $port_list, 'ARRAY') or return;
256              
257 0           my $device = $self->device;
258 0           my $use_ipv6 = $self->use_ipv6;
259              
260 0 0         my $na = Metabrik::Network::Address->new_from_brik_init($self) or return;
261              
262             # Set source IP address.
263 0           my $ip4;
264             my $ip6;
265 0 0         if ($use_ipv6) {
266 0 0         $ip6 = defined($self->src_ip) ? $self->src_ip : $self->my_ipv6;
267 0 0         if (! defined($ip6)) {
268 0           return $self->log->error("tcp_syn_sender: IPv6 not found for device [$device]");
269             }
270             }
271             else {
272 0 0         $ip4 = defined($self->src_ip) ? $self->src_ip : $self->my_ipv4;
273 0 0         if (! defined($ip4)) {
274 0           return $self->log->error("tcp_syn_sender: IPv4 not found for device [$device]");
275             }
276             }
277              
278 0           my $ip = $ip_list->[0];
279 0 0         if ($self->use_ipv6) {
280 0 0         if (! $na->is_ipv6($ip)) {
281 0           return $self->log->error("tcp_syn_sender: address [$ip] is not IPv6 in ip_list");
282             }
283 0           $self->log->verbose("tcp_syn_sender: using source IPv6 [$ip6]");
284             }
285             else {
286 0 0         if (! $na->is_ipv4($ip)) {
287 0           return $self->log->error("tcp_syn_sender: address [$ip] is not IPv4 in ip_list");
288             }
289 0           $self->log->verbose("tcp_syn_sender: using source IPv4 [$ip4]");
290             }
291              
292 0           $self->log->verbose("tcp_syn_sender: sender started");
293              
294             # We have to split by chunks of $chunk_size elements, to avoid taking to
295             # much memory in one row. And there is a SIGSEGV if we don't do so ;)
296 0           my $chunk_size = 1_000_000; # We can load that much into a ARRAYREF before a SIGSEGV
297 0           my $n_targets = scalar(@$ip_list);
298 0           my $n_ports = scalar(@$port_list);
299 0           my $n_chunks = POSIX::ceil($n_targets / $chunk_size);
300 0           for my $n (0..$n_chunks-1) {
301 0           my $first = $chunk_size * $n;
302 0           my $last = ($chunk_size - 1) + ($chunk_size * $n);
303 0 0         if ($last > ($n_targets - 1)) {
304 0           $last = $n_targets - 1;
305             }
306              
307             # By default, we think we scan less than $chunk_size hosts
308 0           my $target_list = $ip_list;
309              
310             # But if we don't, we cut in chunks and $target_list gets a slice
311 0 0         if ($n_chunks > 1) {
312 0           my @this = @$ip_list[$first..$last];
313 0           $target_list = \@this;
314 0           $self->log->verbose("tcp_syn_sender: scanning chunk @{[$n+1]}/@{[($n_chunks)]} ".
  0            
  0            
315             "($first-$last)");
316             }
317              
318 0 0         my $r = Net::Write::Fast::l4_send_tcp_syn_multi(
319             $use_ipv6 ? $ip6 : $ip4,
320             $target_list,
321             $port_list,
322             $pps,
323             $try,
324             $use_ipv6,
325             1, # display warnings or not
326             );
327 0 0         if ($r == 0) {
328 0           $self->log->error("tcp_syn_sender: l4_send_tcp_syn_multi: ".
329             Net::Write::Fast::nwf_geterror());
330             }
331             }
332              
333 0           $self->log->verbose("tcp_syn_sender: sender finished");
334              
335             # We return the number of packets sent
336 0           return $n_targets * $n_ports;
337             }
338              
339             sub tcp_syn_start_receiver {
340 0     0 0   my $self = shift;
341 0           my ($port_list, $filter, $listen_device) = @_;
342              
343 0 0         if (defined($port_list)) {
344 0 0         $self->brik_help_run_invalid_arg('tcp_syn_start_receiver', $port_list, 'ARRAY')
345             or return;
346 0 0         $self->brik_help_run_empty_array_arg('tcp_syn_start_receiver', $port_list)
347             or return;
348             }
349              
350 0   0       $listen_device ||= $self->listen_device;
351              
352 0 0         my $nr = Metabrik::Network::Read->new_from_brik_init($self) or return;
353 0           $nr->filter_code_optimizer($self->filter_code_optimizer);
354              
355 0           my $ip = '';
356 0 0         if ($self->use_ipv6) {
357 0 0         $ip = (defined($self->src_ip) ? $self->src_ip : $self->my_ipv6) or return;
    0          
358             }
359             else {
360 0 0         $ip = (defined($self->src_ip) ? $self->src_ip : $self->my_ipv4) or return;
    0          
361             }
362              
363 0 0         if (defined($port_list)) {
364 0           $self->log->verbose("tcp_syn_start_receiver: scanning for ".scalar(@$port_list).
365             " port(s)");
366             }
367            
368             # Create a filter if not provided by user
369 0 0         if (! defined($filter)) {
370 0 0         $filter = $self->use_ipv6
371             ? 'tcp and (ip6 and dst host '.$ip.')'
372             : 'tcp and (((tcp[13] & 2 != 0) and (tcp[13] & 16 != 0) and dst host '.$ip.')'.
373             ' or '.
374             '((tcp[13] & 4 != 0) and (tcp[13] & 16 != 0) and dst host '.$ip.'))';
375              
376             # If only a few ports specified, we use that in the filter
377 0 0 0       if (defined($port_list) && @$port_list <= 10) {
378 0           $filter .= " and (";
379 0           for (@$port_list) {
380 0           $filter .= "src port $_ or ";
381             }
382 0           $filter =~ s/ or $/)/;
383             }
384             }
385              
386 0           $nr->filter($filter);
387 0           $nr->device($listen_device);
388              
389 0           $self->log->verbose("tcp_syn_start_receiver: using filter [$filter] and ".
390             "device [$listen_device]");
391              
392 0 0         $nr->open or return;
393            
394 0           return $self->_nr($nr);
395             }
396              
397             sub tcp_syn_stop_receiver {
398 0     0 0   my $self = shift;
399              
400 0           my $nr = $self->_nr;
401 0 0         if (! defined($nr)) {
402 0           return 1;
403             }
404              
405 0           $self->log->debug("tcp_syn_stop_receiver: closing nr...");
406 0           $nr->close;
407 0           $self->_nr(undef);
408 0           $self->log->debug("tcp_syn_stop_receiver: closing nr...done");
409              
410 0           return 1;
411             }
412              
413             sub tcp_syn_receive_until_sender_exit {
414 0     0 0   my $self = shift;
415 0           my ($pid, $pps, $wait, $use_ipv6) = @_;
416              
417 0   0       $pps ||= $self->pps;
418 0   0       $wait ||= $self->wait;
419 0           my $nr = $self->_nr;
420 0           $use_ipv6 = 0;
421 0 0         $self->brik_help_run_undef_arg('tcp_syn_receive_until_sender_exit', $pid) or return;
422 0 0         $self->brik_help_run_undef_arg('tcp_syn_receive_until_sender_exit', $pps) or return;
423 0 0         $self->brik_help_run_undef_arg('tcp_syn_receive_until_sender_exit', $wait) or return;
424 0 0         $self->brik_help_run_undef_arg('tcp_syn_start_receiver', $nr) or return;
425              
426 0 0         my $sp = Metabrik::System::Process->new_from_brik_init($self) or return;
427              
428 0           my %open;
429             my %closed;
430 0           while (! $nr->has_timeout) {
431             # We blocking until X frames are read or a Y second timeout has occured
432             # X is calcluted as a ratio of the pps rate.
433 0           $self->log->debug("tcp_syn_receive_until_sender_exit: waiting stuff");
434 0 0         if (my $next = $nr->read_until_timeout($pps / 30, $wait)) {
435 0           $self->log->debug("tcp_syn_receive_until_sender_exit: read_until_timeout has stuff");
436 0           for my $f (@$next) {
437 0           my $s = Net::Frame::Simple->newFromDump($f);
438 0 0         if ($s->ref->{TCP}) {
439 0 0         my $ip = $use_ipv6 ? $s->ref->{IPv6} : $s->ref->{IPv4};
440 0           my $tcp = $s->ref->{TCP};
441 0 0         if ($tcp->flags == 0x12) { # SYN+ACK
    0          
442 0 0         $open{$ip->src}{$tcp->src} = {
    0          
443             ip => $ip->src,
444             port => $tcp->src,
445             id => $use_ipv6 ? $ip->flowLabel : $ip->id,
446             ttl => $use_ipv6 ? $ip->hopLimit : $ip->ttl,
447             win => $tcp->win,
448             opt => unpack('H*', $tcp->options),
449             flags => 'SA',
450             };
451             $self->log->debug("tcp_syn_receive_until_sender_exit: ".sprintf(
452             "tcp %s [%-15s]:%-5d %-5d %-3d %-5d %s",
453             $open{$ip->src}{$tcp->src}->{flags},
454             $ip->src,
455             $tcp->src,
456             $open{$ip->src}{$tcp->src}->{id},
457             $open{$ip->src}{$tcp->src}->{ttl},
458             $open{$ip->src}{$tcp->src}->{win},
459             $open{$ip->src}{$tcp->src}->{opt},
460 0           ),
461             );
462             }
463             elsif ($tcp->flags == 0x14) { # RST+ACK
464 0 0         $closed{$ip->src}{$tcp->src} = {
    0          
465             ip => $ip->src,
466             port => $tcp->src,
467             id => $use_ipv6 ? $ip->flowLabel : $ip->id,
468             ttl => $use_ipv6 ? $ip->hopLimit : $ip->ttl,
469             win => $tcp->win,
470             opt => unpack('H*', $tcp->options),
471             flags => 'RA',
472             };
473             }
474             }
475             }
476 0 0         if ($nr->has_timeout) {
477 0           $self->log->debug("tcp_syn_receive_until_sender_exit: has_timeout");
478 0 0         if (! $sp->is_running($pid)) {
479 0           $self->log->verbose("tcp_syn_receive_until_sender_exit: no more sender, stopping loop");
480 0           last;
481             }
482 0           $self->log->debug("tcp_syn_receive_until_sender_exit: reset_timeout");
483 0           $nr->reset_timeout;
484             }
485             }
486             }
487              
488 0           return { open => \%open, closed => \%closed };
489             }
490              
491             sub tcp_syn_scan {
492 0     0 0   my $self = shift;
493 0           my ($ip_list, $port_list, $pps, $try) = @_;
494              
495 0   0       $port_list ||= $self->ports;
496 0   0       $port_list ||= $self->top100;
497 0   0       $pps ||= $self->pps;
498 0   0       $try ||= $self->try;
499 0 0         $self->brik_help_run_undef_arg('tcp_syn_scan', $ip_list) or return;
500 0 0         my $ref1 = $self->brik_help_run_invalid_arg('tcp_syn_scan', $ip_list, 'ARRAY', 'SCALAR')
501             or return;
502 0 0         if ($ref1 eq 'SCALAR') {
503 0           $ip_list = [ $ip_list ];
504             }
505 0 0         $self->brik_help_run_empty_array_arg('tcp_syn_scan', $ip_list) or return;
506 0 0         $self->brik_help_run_undef_arg('tcp_syn_scan', $port_list, 'ARRAY') or return;
507 0 0         my $ref2 = $self->brik_help_run_invalid_arg('tcp_syn_scan', $port_list, 'ARRAY', 'SCALAR')
508             or return;
509 0 0         if ($ref2 eq 'SCALAR') {
510 0           $port_list = [ $port_list ];
511             }
512 0 0         $self->brik_help_run_empty_array_arg('tcp_syn_scan', $port_list) or return;
513              
514 0           my $wait = $self->wait;
515              
516 0 0         my $na = Metabrik::Network::Address->new_from_brik_init($self) or return;
517              
518 0 0         my $nr = $self->tcp_syn_start_receiver($port_list) or return;
519              
520 0           my $estimate = $self->estimate_runtime($ip_list, $port_list, $pps, $try);
521 0 0         if (defined($estimate)) {
522             my $string = sprintf(
523             "Estimated runtime: %d day(s) %d hour(s) %d minute(s) %d second(s) for %d host(s)",
524             $estimate->{days},
525             $estimate->{hours},
526             $estimate->{minutes},
527             $estimate->{seconds},
528             $estimate->{nhosts},
529 0           );
530 0           $self->log->verbose("tcp_syn_scan: $string");
531             }
532              
533 0           my $start = time();
534              
535             # Fork sender process
536 0 0         my $wf = Metabrik::Worker::Fork->new_from_brik_init($self) or return;
537 0 0         defined(my $pid = $wf->start) or return $self->log->error("tcp_syn_scan: start failed");
538              
539 0 0         if (! $pid) { # Son
540 0           $self->log->debug("tcp_syn_scan: son starts its task...");
541 0           $self->tcp_syn_sender($ip_list, $port_list, $pps, $try);
542 0           $self->log->debug("tcp_syn_scan: son finished its task, exiting");
543 0           exit(0);
544             }
545              
546 0 0         my $use_ipv6 = $na->is_ipv6($ip_list->[0]) ? 1 : 0;
547              
548             # Father: analyse received frames
549 0           $self->log->debug("tcp_syn_scan: father starts");
550 0           my $r = $self->tcp_syn_receive_until_sender_exit($pid, $pps, $wait, $use_ipv6);
551 0           $self->log->debug("tcp_syn_scan: father finished");
552            
553 0           $self->tcp_syn_stop_receiver($nr);
554              
555 0           $self->log->verbose("tcp_syn_scan: completed in ".(time() - $start)." second(s)");
556              
557 0           return $r;
558             }
559              
560             1;
561              
562             __END__