# Masscan::Client

Perl interface for running `masscan` scans and parsing JSON results.

Author and maintainer: Heitor Gouvea `<hgouvea@cpan.org>`

## Requirements

- Perl 5.20+
- `masscan` binary available in `PATH` (or set with `binary`)
- Root/sudo privileges when required by your scan options

## Install

From CPAN:

```bash
cpanm Masscan::Client
```

From a local release tarball:

```bash
cpanm ./Masscan-Client-0.02.tar.gz
```

## Release To CPAN

See [RELEASING.md](RELEASING.md) for the packaging, validation, and PAUSE
upload workflow.

## Quick Start

```perl
use strict;
use warnings;
use Masscan::Client;

my $scanner = Masscan::Client -> new(
    hosts => ['127.0.0.1'],
    ports => [80, 443],
);

$scanner -> add_argument('--rate 10000');

my $ok = $scanner -> scan;
if ($ok) {
    my $result = $scanner -> scan_results;
    print "Up hosts: " . $result -> {masscan} -> {scan_stats} -> {up_hosts} . "\n";
}
```

## Full Example

```perl
use strict;
use warnings;
use Data::Dumper;
use Masscan::Client;

my $scanner = Masscan::Client -> new(
    hosts => ['10.0.0.1', 'scanme.nmap.org'],
    ports => [22, 80, '443', '8000-8100'],
);

$scanner -> verbose(1);
$scanner -> sudo(1);
$scanner -> add_argument('--banners');
$scanner -> add_argument('--rate 100000');

my $success = $scanner -> scan;
if (!$success) {
    die "masscan command failed\n";
}

my $data = $scanner -> scan_results;
print Dumper($data);
```

## What `scan_results` Returns

`scan_results` returns a hash reference with:

- `masscan.command_line`: command executed
- `masscan.scan_stats.total_hosts`: number of input hosts
- `masscan.scan_stats.up_hosts`: hosts with open ports found
- `scan_results`: parsed `masscan` JSON entries

## Main Methods

- `add_host($host)`
- `add_port($port_or_range)`
- `add_argument($argument)`
- `scan()`
- `scan_results()`

## Return Values and Failure Behavior

- `scan()` returns `1` when the `masscan` command exits successfully.
- `scan()` returns `0` when command execution fails.
- `scan_results()` always returns a hash reference; when output cannot be
  parsed, `scan_results` will contain an empty array reference.

Common failure causes:

- `masscan` binary is not found in `PATH`.
- Current user does not have enough privileges for selected scan mode.
- Invalid hosts or ports were provided.

## Constructor Attributes

`Masscan::Client -> new(...)` accepts these attributes:

- `hosts` (`ArrayRef`, default `[]`): IPs, CIDRs, or domains to scan.
- `ports` (`ArrayRef`, default `[]`): ports or ranges like `80` or
  `1000-2000`.
- `arguments` (`ArrayRef`, default `[]`): extra raw `masscan` arguments.
- `binary` (`Str`, default auto-discovered): path to `masscan` binary.
- `scan_results_file` (`Str`, default temp file): output JSON file path.
- `sudo` (`Int`, default `0`): when set to `1`, prefixes command with
  `sudo`.
- `verbose` (`Int`, default `0`): enables debug logging when set to `1`.
- `logger` (`Object`, default internal logger): Log::Log4perl logger.
- `name_servers` (`ArrayRef`, default public resolvers): DNS resolvers
  used for hostnames.

## Generated Command Example

You can inspect the exact command generated by the module after calling
`scan()`:

```perl
use strict;
use warnings;
use Masscan::Client;

my $scanner = Masscan::Client -> new(
    hosts => ['127.0.0.1'],
    ports => [80, 443],
);

$scanner -> add_argument('--rate 10000');
$scanner -> scan;

print $scanner -> command_line . "\n";
```

Example output:

```text
/usr/bin/masscan --rate 10000 -p 80,443 127.0.0.1
```

## Notes

- Domain hosts are resolved through DNS (`A` and `AAAA`).
- Custom DNS servers can be set with `name_servers([...])`.
- The output file is managed internally via a temporary file.

## Privileges and Security

- Many scan modes require elevated privileges (`root` or `sudo`).
- Port scanning can violate network policy or law if done without
  authorization.
- Run scans only against assets you own or are explicitly allowed to test.

## Minimal Verification Script

Use this script to validate that installation and basic execution work:

```perl
use strict;
use warnings;
use Masscan::Client;

my $scanner = Masscan::Client -> new(
    hosts => ['127.0.0.1'],
    ports => [80],
);

$scanner -> add_argument('--rate 1000');

my $ok = $scanner -> scan;
if (!$ok) {
    die "scan failed\n";
}

my $result = $scanner -> scan_results;
print "total_hosts=" . $result -> {masscan} -> {scan_stats} -> {total_hosts} . "\n";
print "up_hosts=" . $result -> {masscan} -> {scan_stats} -> {up_hosts} . "\n";
```

## License

This distribution is free software; you can redistribute it and/or
modify it under the same terms as Perl 5.
