From 27f036eee1230956ae45a12161675d0248e923a2 Mon Sep 17 00:00:00 2001 From: Hosteroid Date: Wed, 11 Mar 2026 14:57:56 +0200 Subject: [PATCH] Query MX/TXT for subdomains; add host column Add MX and TXT queries to DnsService probing flows (initial, special, and deep scan) by removing the previous TXT-only conditional and explicitly querying DNS_MX and DNS_TXT. Extend sortRecords to include A, AAAA, MX, TXT, and CAA and sort by root (@) first, then by host, and by priority when present. Update DNS views to show a Host column for MX, TXT, and CAA tables, display @ as "@ (root)", and surface record source badges (manual/imported) next to the host for clarity. --- app/Services/DnsService.php | 29 ++++++++++------- app/Views/domains/tabs/dns.twig | 57 ++++++++++++++++++++++++--------- 2 files changed, 59 insertions(+), 27 deletions(-) diff --git a/app/Services/DnsService.php b/app/Services/DnsService.php index dafb5ae..8b02ce7 100644 --- a/app/Services/DnsService.php +++ b/app/Services/DnsService.php @@ -106,9 +106,8 @@ class DnsService $this->queryAndCollect($fqdn, DNS_A, 'A', $domain, $records, $seen); $this->queryAndCollect($fqdn, DNS_AAAA, 'AAAA', $domain, $records, $seen); $this->queryAndCollect($fqdn, DNS_CNAME, 'CNAME', $domain, $records, $seen); - if (in_array($sub, ['_dmarc', '_mta-sts', '_domainkey']) || str_starts_with($sub, '_')) { - $this->queryAndCollect($fqdn, DNS_TXT, 'TXT', $domain, $records, $seen); - } + $this->queryAndCollect($fqdn, DNS_MX, 'MX', $domain, $records, $seen); + $this->queryAndCollect($fqdn, DNS_TXT, 'TXT', $domain, $records, $seen); } foreach (self::SPECIAL_TXT_SUBDOMAINS as $sub) { @@ -147,6 +146,8 @@ class DnsService $this->queryAndCollect($fqdn, DNS_A, 'A', $domain, $records, $seen); $this->queryAndCollect($fqdn, DNS_AAAA, 'AAAA', $domain, $records, $seen); $this->queryAndCollect($fqdn, DNS_CNAME, 'CNAME', $domain, $records, $seen); + $this->queryAndCollect($fqdn, DNS_MX, 'MX', $domain, $records, $seen); + $this->queryAndCollect($fqdn, DNS_TXT, 'TXT', $domain, $records, $seen); } foreach (self::SPECIAL_TXT_SUBDOMAINS as $sub) { @@ -222,7 +223,7 @@ class DnsService } $log("Subdomain probe complete: " . count($discovered) . " found out of {$total}"); - // Deep scan discovered subdomains (A, AAAA, CNAME, TXT) + // Deep scan discovered subdomains if (!empty($discovered)) { $log("Querying " . count($discovered) . " discovered subdomain(s)..."); } @@ -231,9 +232,8 @@ class DnsService $this->queryAndCollect($fqdn, DNS_A, 'A', $domain, $records, $seen); $this->queryAndCollect($fqdn, DNS_AAAA, 'AAAA', $domain, $records, $seen); $this->queryAndCollect($fqdn, DNS_CNAME, 'CNAME', $domain, $records, $seen); - if (in_array($sub, ['_dmarc', '_mta-sts', '_domainkey']) || str_starts_with($sub, '_')) { - $this->queryAndCollect($fqdn, DNS_TXT, 'TXT', $domain, $records, $seen); - } + $this->queryAndCollect($fqdn, DNS_MX, 'MX', $domain, $records, $seen); + $this->queryAndCollect($fqdn, DNS_TXT, 'TXT', $domain, $records, $seen); } $log("Querying special TXT subdomains..."); @@ -452,15 +452,20 @@ class DnsService } /** - * Sort A/AAAA records: root (@) first, then alphabetical by host. + * Sort records: root (@) first, then alphabetical by host. */ private function sortRecords(array &$records): void { - foreach (['A', 'AAAA'] as $type) { + foreach (['A', 'AAAA', 'MX', 'TXT', 'CAA'] as $type) { + if (empty($records[$type])) { + continue; + } usort($records[$type], function ($a, $b) { - if ($a['host'] === '@') return -1; - if ($b['host'] === '@') return 1; - return strcmp($a['host'], $b['host']); + if ($a['host'] === '@' && $b['host'] !== '@') return -1; + if ($b['host'] === '@' && $a['host'] !== '@') return 1; + $hostCmp = strcmp($a['host'], $b['host']); + if ($hostCmp !== 0) return $hostCmp; + return ($a['priority'] ?? 0) <=> ($b['priority'] ?? 0); }); } } diff --git a/app/Views/domains/tabs/dns.twig b/app/Views/domains/tabs/dns.twig index 7560746..273955c 100644 --- a/app/Views/domains/tabs/dns.twig +++ b/app/Views/domains/tabs/dns.twig @@ -408,6 +408,7 @@ + Host Priority Mail Server TTL @@ -418,12 +419,20 @@ {% for record in dnsRecords['MX'] %} + + {% if record.host == '@' %} + @ (root) + {% else %} + {{ record.host }} + {% endif %} + {% if record.source|default('discovered') == 'manual' %} + manual + {% elseif record.source|default('discovered') == 'imported' %} + imported + {% endif %} + - {{ record.priority }}{% if record.source|default('discovered') == 'manual' %} - manual - {% elseif record.source|default('discovered') == 'imported' %} - imported - {% endif %} + {{ record.priority }} {{ record.value }} {{ record.ttl }}s @@ -458,6 +467,7 @@ + Host Type Value TTL @@ -484,12 +494,20 @@ {% endif %} + + {% if record.host == '@' %} + @ (root) + {% else %} + {{ record.host }} + {% endif %} + {% if record.source|default('discovered') == 'manual' %} + manual + {% elseif record.source|default('discovered') == 'imported' %} + imported + {% endif %} + - {{ txtType }}{% if record.source|default('discovered') == 'manual' %} - manual - {% elseif record.source|default('discovered') == 'imported' %} - imported - {% endif %} + {{ txtType }} {{ record.value }} {{ record.ttl }}s @@ -643,6 +661,7 @@ + Host Tag Value (CA) Flags @@ -655,12 +674,20 @@ {% set rawData = record.raw_data ? record.raw_data|from_json : {} %} + + {% if record.host == '@' %} + @ (root) + {% else %} + {{ record.host }} + {% endif %} + {% if record.source|default('discovered') == 'manual' %} + manual + {% elseif record.source|default('discovered') == 'imported' %} + imported + {% endif %} + - {{ rawData.tag|default('-') }}{% if record.source|default('discovered') == 'manual' %} - manual - {% elseif record.source|default('discovered') == 'imported' %} - imported - {% endif %} + {{ rawData.tag|default('-') }} {{ rawData.value|default(record.value) }} {{ rawData.flags|default('0') }}