270 lines
10 KiB
PHP
270 lines
10 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire\Ui\Domain\Modal;
|
|
|
|
use App\Models\Domain;
|
|
use App\Models\TlsaRecord;
|
|
use App\Support\NetProbe;
|
|
use Illuminate\Support\Facades\DB;
|
|
use LivewireUI\Modal\ModalComponent;
|
|
|
|
class DomainDnsModal extends ModalComponent
|
|
{
|
|
public int $domainId;
|
|
public string $domainName = '';
|
|
public string $zone = '';
|
|
public string $ttl = '3600';
|
|
public array $recordColors = [];
|
|
|
|
/** @var array<int,array<string,string|int|null>> */
|
|
public array $static = [];
|
|
/** @var array<int,array<string,string|int|null>> */
|
|
public array $dynamic = [];
|
|
|
|
public static function modalMaxWidth(): string
|
|
{
|
|
return '6xl';
|
|
}
|
|
|
|
public function mount(int $domainId): void
|
|
{
|
|
$this->recordColors = [
|
|
'A' => 'bg-cyan-500/20 text-cyan-300',
|
|
'AAAA' => 'bg-blue-500/20 text-blue-300',
|
|
'MX' => 'bg-emerald-500/20 text-emerald-300',
|
|
'CNAME' => 'bg-indigo-500/20 text-indigo-300',
|
|
'PTR' => 'bg-amber-500/20 text-amber-300',
|
|
'TXT' => 'bg-violet-500/20 text-violet-300',
|
|
'SRV' => 'bg-rose-500/20 text-rose-300',
|
|
'TLSA' => 'bg-red-500/20 text-red-300',
|
|
];
|
|
|
|
$d = Domain::findOrFail($domainId);
|
|
$this->domainName = $d->domain;
|
|
|
|
$tlsa = TlsaRecord::forServer()
|
|
->where('service', '_25._tcp')
|
|
->latest('id')
|
|
->first();
|
|
|
|
$ips = NetProbe::resolve();
|
|
$ipv4 = $ips['ipv4'];
|
|
$ipv6 = $ips['ipv6'];
|
|
|
|
$this->zone = $this->extractZone($d->domain);
|
|
$mta_sub = env('MTA_SUB');
|
|
$base = env('BASE_DOMAIN');
|
|
$mailServerFqdn = $mta_sub . '.' . $base;
|
|
$mta = $mta_sub . '.' . $this->zone;
|
|
|
|
// --- Statische Infrastruktur (für alle Domains gleich) ---
|
|
$this->static = [
|
|
['type' => 'MX', 'name' => $base, 'value' => "10 {$mailServerFqdn}."],
|
|
['type' => 'A', 'name' => $mailServerFqdn, 'value' => $ipv4],
|
|
['type' => 'PTR', 'name' => $this->ptrFromIPv4($ipv4), 'value' => $tlsa->host],
|
|
];
|
|
if ($ipv6) {
|
|
$this->static[] = ['type' => 'AAAA', 'name' => $mailServerFqdn, 'value' => $ipv6];
|
|
$this->static[] = ['type' => 'PTR', 'name' => $this->ptrFromIPv6($ipv6), 'value' => $mailServerFqdn];
|
|
}
|
|
|
|
|
|
if ($tlsa?->dns_string) {
|
|
$this->static[] = [
|
|
'type' => 'TLSA',
|
|
'name' => "{$tlsa->service}.{$tlsa->host}",
|
|
'value' => "{$tlsa->usage} {$tlsa->selector} {$tlsa->matching} {$tlsa->hash}",
|
|
];
|
|
}
|
|
|
|
// --- Domain-spezifisch ---
|
|
$spf = "v=spf1 a mx ip4:{$ipv4} ip6:{$ipv6} ~all";
|
|
$dmarc = "v=DMARC1; p=none; rua=mailto:dmarc@{$this->domainName}; pct=100";
|
|
|
|
$dkim = DB::table('dkim_keys')
|
|
->where('domain_id', $d->id)->where('is_active', 1)->orderByDesc('id')->first();
|
|
$selector = $dkim ? $dkim->selector : 'mwl1';
|
|
$dkimHost = "{$selector}._domainkey.{$this->domainName}";
|
|
$dkimTxt = $dkim && !str_starts_with(trim($dkim->public_key_txt), 'v=')
|
|
? 'v=DKIM1; k=rsa; p=' . $dkim->public_key_txt
|
|
: ($dkim->public_key_txt ?? 'v=DKIM1; k=rsa; p=');
|
|
|
|
$this->dynamic = [
|
|
['type' => 'CNAME', 'name' => "autoconfig.$this->domainName", 'value' => "$mailServerFqdn."],
|
|
['type' => 'CNAME', 'name' => "autodiscover.$this->domainName", 'value' => "$mailServerFqdn."],
|
|
|
|
// SRV Records für Autodiscover und Maildienste
|
|
['type' => 'SRV', 'name' => "_autodiscover._tcp.$this->domainName", 'value' => "0 0 443 {$mailServerFqdn}."],
|
|
['type' => 'SRV', 'name' => "_imaps._tcp.$this->domainName", 'value' => "0 0 993 {$mailServerFqdn}."],
|
|
['type' => 'SRV', 'name' => "_pop3s._tcp.$this->domainName", 'value' => "0 0 995 {$mailServerFqdn}."],
|
|
['type' => 'SRV', 'name' => "_submission._tcp.$this->domainName", 'value' => "0 0 587 {$mailServerFqdn}."],
|
|
|
|
// TXT Records
|
|
['type' => 'TXT', 'name' => $this->domainName, 'value' => $spf, 'helpLabel' => 'SPF Record Syntax', 'helpUrl' => 'http://www.open-spf.org/SPF_Record_Syntax/'],
|
|
['type' => 'TXT', 'name' => "_dmarc.{$this->domainName}", 'value' => $dmarc, 'helpLabel' => 'DMARC Assistant', 'helpUrl' => 'https://www.kitterman.com/dmarc/assistant.html'],
|
|
['type' => 'TXT', 'name' => $dkimHost, 'value' => $dkimTxt, 'helpLabel' => 'DKIM Inspector', 'helpUrl' => 'https://dkimvalidator.com/'],
|
|
];
|
|
}
|
|
|
|
private function extractZone(string $fqdn): string
|
|
{
|
|
$fqdn = strtolower(trim($fqdn, "."));
|
|
$parts = explode('.', $fqdn);
|
|
$n = count($parts);
|
|
return $n >= 2 ? $parts[$n - 2] . '.' . $parts[$n - 1] : $fqdn; // nimmt die letzten 2 Labels
|
|
}
|
|
|
|
private function detectIPv4(): string
|
|
{
|
|
// robust & ohne env
|
|
$out = @shell_exec("ip -4 route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if(\$i==\"src\"){print \$(i+1); exit}}'");
|
|
$ip = trim((string)$out);
|
|
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) return $ip;
|
|
$ip = trim($_SERVER['SERVER_ADDR'] ?? '');
|
|
return $ip ?: '203.0.113.10'; // Fallback Demo
|
|
}
|
|
|
|
private function detectIPv6(): ?string
|
|
{
|
|
$out = @shell_exec("ip -6 route get 2001:4860:4860::8888 2>/dev/null | awk '{for(i=1;i<=NF;i++) if(\$i==\"src\"){print \$(i+1); exit}}'");
|
|
$ip = trim((string)$out);
|
|
return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ? $ip : null;
|
|
}
|
|
|
|
private function ptrFromIPv4(string $ip): string
|
|
{
|
|
$p = array_reverse(explode('.', $ip));
|
|
return implode('.', $p) . '.in-addr.arpa';
|
|
}
|
|
|
|
private function ptrFromIPv6(string $ip): string
|
|
{
|
|
$expanded = strtolower(inet_ntop(inet_pton($ip)));
|
|
$hex = str_replace(':', '', $expanded);
|
|
return implode('.', array_reverse(str_split($hex))) . '.ip6.arpa';
|
|
}
|
|
|
|
public function render()
|
|
{
|
|
return view('livewire.ui.domain.modal.domain-dns-modal');
|
|
}
|
|
|
|
// public int $domainId;
|
|
// public Domain $domain;
|
|
//
|
|
// public array $records = [];
|
|
//
|
|
// public function mount(int $domainId): void
|
|
// {
|
|
// $this->domainId = $domainId;
|
|
// $this->domain = Domain::findOrFail($domainId);
|
|
//
|
|
// // Placeholder-Werte, sofern du sie anderswo speicherst gern ersetzen:
|
|
// $serverIp = config('app.server_ip', 'DEINE.SERVER.IP');
|
|
// $mxHost = config('mailwolt.mx_fqdn', 'mx.' . $this->domain->domain);
|
|
// $selector = optional(
|
|
// DkimKey::where('domain_id', $this->domain->id)->where('is_active', true)->first()
|
|
// )->selector ?? 'mwl1';
|
|
//
|
|
// $dkimTxt = optional(
|
|
// DkimKey::where('domain_id', $this->domain->id)->where('is_active', true)->first()
|
|
// )->public_key_txt ?? 'DKIM_PUBLIC_KEY';
|
|
//
|
|
// $this->records = [
|
|
// [
|
|
// 'type' => 'A',
|
|
// 'host' => $this->domain->domain,
|
|
// 'value' => $serverIp,
|
|
// 'ttl' => 3600,
|
|
// ],
|
|
// [
|
|
// 'type' => 'MX',
|
|
// 'host' => $this->domain->domain,
|
|
// 'value' => "10 {$mxHost}.",
|
|
// 'ttl' => 3600,
|
|
// ],
|
|
// [
|
|
// 'type' => 'TXT',
|
|
// 'host' => $this->domain->domain,
|
|
// 'value' => 'v=spf1 mx a -all',
|
|
// 'ttl' => 3600,
|
|
// ],
|
|
// [
|
|
// 'type' => 'TXT',
|
|
// 'host' => "{$selector}._domainkey." . $this->domain->domain,
|
|
// // komplette, fertige TXT-Payload (aus deiner dkim_keys.public_key_txt Spalte)
|
|
// 'value' => "v=DKIM1; k=rsa; p={$dkimTxt}",
|
|
// 'ttl' => 3600,
|
|
// ],
|
|
// [
|
|
// 'type' => 'TXT',
|
|
// 'host' => "_dmarc." . $this->domain->domain,
|
|
// 'value' => "v=DMARC1; p=none; rua=mailto:dmarc@" . $this->domain->domain . "; pct=100",
|
|
// 'ttl' => 3600,
|
|
// ],
|
|
// ];
|
|
// }
|
|
//
|
|
// public static function modalMaxWidth(): string
|
|
// {
|
|
// return '4xl'; // schön breit
|
|
// }
|
|
//
|
|
// public function render()
|
|
// {
|
|
// return view('livewire.ui.domain.modal.domain-dns-modal');
|
|
// }
|
|
|
|
// public Domain $domain;
|
|
//
|
|
// public static function modalMaxWidth(): string
|
|
// {
|
|
// return '3xl';
|
|
// }
|
|
//
|
|
// public function mount(int $domainId): void
|
|
// {
|
|
// $this->domain = Domain::with(['dkimKeys' /* falls Relationen existieren */])->findOrFail($domainId);
|
|
// }
|
|
//
|
|
// public function render()
|
|
// {
|
|
// // Hier kannst du die Records vorbereiten (SPF/DMARC/DKIM)
|
|
// $records = [
|
|
// [
|
|
// 'type' => 'TXT',
|
|
// 'host' => $this->domain->domain,
|
|
// 'value'=> $this->domain->spf_record ?? 'v=spf1 mx a -all',
|
|
// 'ttl' => 3600,
|
|
// ],
|
|
// [
|
|
// 'type' => 'TXT',
|
|
// 'host' => '_dmarc.' . $this->domain->domain,
|
|
// 'value'=> $this->domain->dmarc_record ?? 'v=DMARC1; p=none; rua=mailto:dmarc@' . $this->domain->domain . '; pct=100',
|
|
// 'ttl' => 3600,
|
|
// ],
|
|
// // DKIM (falls vorhanden)
|
|
// // Beispiel: nimm den aktiven Key oder den ersten
|
|
// ];
|
|
//
|
|
// $dkim = optional($this->domain->dkimKeys()->where('is_active', true)->first() ?? $this->domain->dkimKeys()->first());
|
|
// if ($dkim && $dkim->selector) {
|
|
// $records[] = [
|
|
// 'type' => 'TXT',
|
|
// 'host' => "{$dkim->selector}._domainkey." . $this->domain->domain,
|
|
// 'value'=> "v=DKIM1; k=rsa; p={$dkim->public_key_txt}",
|
|
// 'ttl' => 3600,
|
|
// ];
|
|
// }
|
|
//
|
|
// return view('livewire.ui.domain.modal.domain-dns-modal', [
|
|
// 'records' => $records,
|
|
// ]);
|
|
// }
|
|
|
|
// public function render()
|
|
// {
|
|
// return view('livewire.ui.domain.modal.domain-dns-modal');
|
|
// }
|
|
}
|