*/ private const RECORD_TYPES = [ 'A' => DNS_A, 'AAAA' => DNS_AAAA, 'MX' => DNS_MX, 'NS' => DNS_NS, 'TXT' => DNS_TXT, 'CNAME' => DNS_CNAME, ]; public function run(Target $target): RunnerResult { if ($target->type !== 'domain') { throw new RunnerException('DNS lookup only supports "domain" targets.'); } if (! preg_match('/^([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/', $target->value)) { throw new RunnerException('Domain contains characters that are not safe to look up.'); } $records = []; foreach (self::RECORD_TYPES as $label => $type) { // dns_get_record() emits a warning (not an exception) when a // record type doesn't resolve for the domain — expected for // most domains on most types, not a real error. $found = @dns_get_record($target->value, $type); if ($found === false || empty($found)) { continue; } $records[$label] = array_values(array_unique(array_map( fn (array $record) => $this->formatRecord($label, $record), $found ))); } $total = array_sum(array_map('count', $records)); $summary = $total > 0 ? sprintf('Found %d DNS record%s across %d type%s (%s).', $total, $total === 1 ? '' : 's', count($records), count($records) === 1 ? '' : 's', implode(', ', array_keys($records))) : 'No DNS records found.'; return new RunnerResult(raw: $records, summary: $summary); } private function formatRecord(string $label, array $record): string { return match ($label) { 'A', 'AAAA' => $record['ip'] ?? '', 'MX' => sprintf('%d %s', $record['pri'] ?? 0, $record['target'] ?? ''), 'NS', 'CNAME' => $record['target'] ?? '', 'TXT' => $record['txt'] ?? '', default => '', }; } }