scanHost function

Future<Map<int, Map<String, dynamic>>> scanHost(
  1. String host,
  2. List<int> ports, {
  3. int portConcurrency = 50,
  4. Duration timeout = const Duration(milliseconds: 300),
  5. Duration bannerTimeout = const Duration(milliseconds: 300),
})

Scan a single host's ports and attempt a small banner grab for each open port. Returns a map port->optional banner (null if none captured). Returns port -> { 'banner': String?, 'protocol': String? }

Implementation

Future<Map<int, Map<String, dynamic>>> scanHost(
  String host,
  List<int> ports, {
  int portConcurrency = 50,
  Duration timeout = const Duration(milliseconds: 300),
  Duration bannerTimeout = const Duration(milliseconds: 300),
}) async {
  final result = <int, Map<String, dynamic>>{};
  final sem = Pool(portConcurrency);
  final futures = <Future>[];

  for (final p in ports) {
    futures.add(
      sem.withResource(() async {
        final measuredTimeout = _adaptiveTimeoutForHost(host, timeout);
        try {
          // Use the separated socket probe to perform a small banner grab.
          final banner = await socket_probe.grabBanner(
            host,
            p,
            timeout: measuredTimeout,
            bannerTimeout: bannerTimeout,
          );
          final proto =
              banner != null ? identifyProtocolFromBanner(banner) : null;
          final svc = _wellKnownPortService(p);
          final sev = _serviceSeverity(svc, p);
          result[p] = {
            'banner': banner,
            'protocol': proto,
            'service': svc,
            'severity': sev,
          };
          // socket_probe handles socket lifecycle
        } catch (_) {
          // closed or filtered
        }
      }),
    );
  }

  await Future.wait(futures);
  final orderedPorts = result.keys.toList()..sort();
  final sorted = <int, Map<String, dynamic>>{};
  for (final k in orderedPorts) {
    sorted[k] = result[k]!;
  }
  return sorted;
}