TCP scanner
Simple and fast TCP scanner.
Usage
TcpScannerTask
TcpScannerTask allows you to execute scanning tasks asynchronously and provides basic methods to control task.
You can set shuffle
to true if you need to shuffle ports. By default, socket connect timeout is 2 seconds.
After this time the port will be marked as closed
if the response wouldn't receive.
You may change this value by setting socketTimeout
option. By default socketTimeout
equals to 100 ms. You can specify the number of isolates to scan by
defining parallelism
option. By default, parallelism equals 4.
To execute simple task use start method and wait for result.
final host = '192.168.88.229';
final ports = List.generate(990, (i) => 10 + i)
..add(5000)
..addAll([1100, 1110]);
var stopwatch = Stopwatch();
stopwatch.start();
try {
await TcpScannerTask(host, ports, shuffle: true, parallelism: 2)
.start()
.then((report) => print('Host ${report.host} scan completed\n'
'Scanned ports:\t${report.ports.length}\n'
'Open ports:\t${report.openPorts}\n'
'Status:\t${report.status}\n'
'Elapsed:\t${stopwatch.elapsed}\n'))
// Catch errors during the scan
.catchError((error) => stderr.writeln(error));
} catch (e) {
// Here you can catch exceptions threw in the constructor
stderr.writeln('Error: $e');
}
Task can be cancelled using cancel()
method. It returns a Future with the result of the scan.
The cancel
method can throw TcpScannerTaskException
if task had already finished.
Pay attention that in case of cancelling a Future from the start()
method won't be returned.
For example, if you will use await scannerTask.start()
you will never get the result.
var ports = List.generate(65535, (i) => 0 + i);
var stopwatch2 = Stopwatch();
stopwatch2.start();
try {
var scannerTask1 = TcpScannerTask(host, ports);
Future.delayed(Duration(seconds: 2), () {
print('ScannerTask cancelled by timeout after ${stopwatch2.elapsed}');
scannerTask1
.cancel()
.then((report) => print('Host ${report.host} scan was cancelled\n'
'Scanned ports:\t${report.openPorts.length + report.closedPorts.length}\n'
'Open ports:\t${report.openPorts}\n'
'Status:\t${report.status}\n'
'Elapsed:\t${stopwatch2.elapsed}\n'))
.catchError((error) => stderr.writeln(error));
});
scannerTask1.start();
} catch (error) {
stderr.writeln(error);
}
You can request a status during the scanning using the report
field:
var ports = List.generate(65535, (i) => 0 + i);
var stopwatch3 = Stopwatch();
stopwatch3.start();
try {
var scannerTask2 = TcpScannerTask(host, ports, parallelism: 100);
Timer.periodic(Duration(seconds: 1), (timer) {
scannerTask2.report.then((report) {
var percents = 100.0 * (report.openPorts.length + report.closedPorts.length) / report.ports.length;
var scanned = report.closedPorts.length + report.openPorts.length;
print('Host $host scan progress ${percents.toStringAsFixed(1)}%\n'
'Scanned ports:\t$scanned of ${report.ports.length}\n'
'Open ports:\t${report.openPorts}\n'
'Status:\t${report.status}\n'
'Elapsed:\t${stopwatch3.elapsed}\n');
if (report.status == TcpScannerTaskReportStatus.finished) {
timer.cancel();
}
});
});
await scannerTask2.start();
} catch (error) {
stderr.writeln(error);
}
TCPScanner
This class is deprecated, and it is highly recommended to use TcpScannerTask instead of TCPScanner.
It's easy to scan a host. You just need to create the TCPScanner
instance and call scan
method. The result is stored in ScanResult
data object.
Scan specified ports:
import 'package:tcp_scanner/tcp_scanner.dart';
main() {
TCPScanner("localhost", [ 80, 8080, 443 ]).scan().then((result) {
print('''
HTTP ports scan result
Host: ${result.host}
Scanned ports: ${result.ports}
Open ports: ${result.open}
Closed ports: ${result.closed}
Elapsed time: ${result.elapsed / 1000}s
''');
});
}
If host is reachable and ports are closed output will be:
HTTP ports scan result
Host: localhost
Scanned ports: [80, 8080, 443]
Open ports: []
Closed ports: [80, 8080, 443]
Elapsed time: 0.03s
Sometimes you can not get response from the host or from specified port because of firewall or IDS. In this case port will be marked as closed
. To define connection establishment timeout you should use timeout
argumnet in the constructor. By default, timeout is 100ms.
Scan in the following example elapsed about 900 ms because it was scanned 3 ports of the unreachable host with 300ms timeout.
import 'package:tcp_scanner/tcp_scanner.dart';
main() {
TCPScanner(
"192.168.1.1",
[
80,
8080,
443
],
timeout: 100)
.scan()
.then((result) {
print('''
HTTP ports scan result
Host: ${result.host}
Scanned ports: ${result.ports}
Open ports: ${result.open}
Closed ports: ${result.closed}
Elapsed time: ${result.elapsed / 1000}s
''');
});
}
Output:
HTTP ports scan result
Host: 192.168.1.1
Scanned ports: [80, 8080, 443]
Open ports: []
Closed ports: [80, 8080, 443]
Elapsed time: 1.016s
You can use TCPScanner.range
constructor if you want to scan ports range:
import 'package:tcp_scanner/tcp_scanner.dart';
main() {
TCPScanner.range("127.0.0.1", 20, 1000).scan().then((result) {
print('''
20-1000 ports scan result
Host: ${result.host}
Scanned ports: 20-1000
Open ports: ${result.open}
Elapsed time: ${result.elapsed / 1000}s
''');
});
}
You can get the current status while scan is running. Just use TCPScanner.scanResult
to get current status. You can control update interval by updateInterval
parameter. By default, update interval is 1 second. Getting information about running scan:
import 'dart:async';
import 'package:tcp_scanner/tcp_scanner.dart';
main() {
var tcpScanner = TCPScanner.range("127.0.0.1", 20, 50000, updateInterval: Duration(seconds: 5));
var timer = Timer.periodic(Duration(seconds: 1), (timer) {
var scanProgress = 100.0 * (tcpScanner.scanResult.scanned.length / tcpScanner.scanResult.ports.length);
print("Progress ${scanProgress.toStringAsPrecision(3)}%");
});
tcpScanner.scan().then((result) {
timer.cancel();
print('''
20-50000 ports scan result
Host: ${result.host}
Scanned ports: 20-50000
Open ports: ${result.open}
Elapsed time: ${result.elapsed / 1000}s
''');
});
}
Output:
Progress 0.00%
Progress 7.99%
Progress 18.2%
Progress 28.2%
Progress 38.2%
Progress 48.8%
Progress 59.6%
Progress 70.4%
Progress 81.1%
20-50000 ports scan result
Host: 127.0.0.1
Scanned ports: 20-50000
Open ports: [1024, 1025, 1026, 1027, 1028, 1029, 29754]
Elapsed time: 9.841s
You can improve perfomance by set isolates
argument. Also, you can shuffle ports using shuffle
option.
var multithreadedScanner = TCPScanner.range("127.0.0.1", 20, 5000, isolates: 10, shuffle: true);
var multithreadedTimer = Timer.periodic(Duration(seconds: 1), (timer) {
var scanProgress = 100.0 * (multithreadedScanner.scanResult.scanned.length / multithreadedScanner.scanResult.ports.length);
print("Progress ${scanProgress.toStringAsPrecision(3)}%");
});
multithreadedScanner.scan().then((result) {
multithreadedTimer.cancel();
print('''
20-5000 ports scan result
Host: ${result.host}
Scanned ports: 20-5000
Open ports: ${result.open}
Elapsed time: ${result.elapsed / 1000}s
''');
});
Open ports is shuffled in the report because shuffle
option was used and ports were scanned in a random order. Ports will be shuffled each call of scan()
.
Progress 0.00%
Progress 21.5%
Progress 52.4%
20-50000 ports scan result
Host: 127.0.0.1
Scanned ports: 20-50000
Open ports: [1028, 1029, 1024, 1027, 29754, 1026, 1025]
Elapsed time: 3.535s
Features and bugs
Please file feature requests and bugs at the issue tracker.
Libraries
- tcp_scanner
- TCP port scanner