From 1afb509c3322192f93381976bf3b235e8b8e74af Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 15 Jan 2024 10:03:15 +0100 Subject: [PATCH] add domain validation + custom dns servers add new guides / docs --- app/Livewire/Project/Application/General.php | 13 +++-- app/Livewire/Server/Form.php | 4 +- app/Livewire/Server/ShowPrivateKey.php | 2 +- app/Livewire/Settings/Configuration.php | 13 +++++ bootstrap/helpers/proxy.php | 2 +- bootstrap/helpers/shared.php | 51 +++++++++++++++++-- composer.json | 1 + composer.lock | 50 +++++++++++++++++- ...024_01_15_084609_add_custom_dns_server.php | 30 +++++++++++ .../livewire/settings/configuration.blade.php | 4 +- 10 files changed, 158 insertions(+), 12 deletions(-) create mode 100644 database/migrations/2024_01_15_084609_add_custom_dns_server.php diff --git a/app/Livewire/Project/Application/General.php b/app/Livewire/Project/Application/General.php index 0c5828af3..ab16f64d7 100644 --- a/app/Livewire/Project/Application/General.php +++ b/app/Livewire/Project/Application/General.php @@ -209,7 +209,7 @@ public function resetDefaultLabels($showToaster = true) public function updatedApplicationFqdn() { $this->resetDefaultLabels(false); - $this->dispatch('success', 'Labels reset to default!'); + // $this->dispatch('success', 'Labels reset to default!'); } public function submit($showToaster = true) { @@ -235,9 +235,16 @@ public function submit($showToaster = true) ]); } if (data_get($this->application, 'fqdn')) { - $domains = Str::of($this->application->fqdn)->trim()->explode(',')->map(function ($domain) { - return Str::of($domain)->trim()->lower(); + $this->application->fqdn = str($this->application->fqdn)->replaceEnd(',', '')->trim(); + $domains = str($this->application->fqdn)->trim()->explode(',')->map(function ($domain) { + return str($domain)->trim()->lower(); }); + $domains = $domains->unique(); + foreach ($domains as $domain) { + if (!validate_dns_entry($domain, $this->application->destination->server)) { + $showToaster && $this->dispatch('error', "Validating DNS settings for: $domain failed.
Make sure you have added the DNS records correctly.

Check this documentation for further help."); + } + } $this->application->fqdn = $domains->implode(','); } diff --git a/app/Livewire/Server/Form.php b/app/Livewire/Server/Form.php index 466ca5472..d832c83d8 100644 --- a/app/Livewire/Server/Form.php +++ b/app/Livewire/Server/Form.php @@ -76,7 +76,7 @@ public function checkLocalhostConnection() $this->server->settings->is_usable = true; $this->server->settings->save(); } else { - $this->dispatch('error', 'Server is not reachable.
Please validate your configuration and connection. See this documentation.'); + $this->dispatch('error', 'Server is not reachable.
Please validate your configuration and connection.

Check this documentation for further help.'); return; } } @@ -85,7 +85,7 @@ public function validateServer($install = true) try { $uptime = $this->server->validateConnection(); if (!$uptime) { - $install && $this->dispatch('error', 'Server is not reachable.
Please validate your configuration and connection. See this documentation.'); + $install && $this->dispatch('error', 'Server is not reachable.
Please validate your configuration and connection.

Check this documentation for further help.'); return; } $supported_os_type = $this->server->validateOS(); diff --git a/app/Livewire/Server/ShowPrivateKey.php b/app/Livewire/Server/ShowPrivateKey.php index a39765c71..0834866c1 100644 --- a/app/Livewire/Server/ShowPrivateKey.php +++ b/app/Livewire/Server/ShowPrivateKey.php @@ -39,7 +39,7 @@ public function checkConnection() if ($uptime) { $this->dispatch('success', 'Server is reachable.'); } else { - $this->dispatch('error', 'Server is not reachable.
Please validate your configuration and connection. See this documentation.'); + $this->dispatch('error', 'Server is not reachable.
Please validate your configuration and connection.

Check this documentation for further help.'); return; } } catch (\Throwable $e) { diff --git a/app/Livewire/Settings/Configuration.php b/app/Livewire/Settings/Configuration.php index 43f4afb7a..bafc82447 100644 --- a/app/Livewire/Settings/Configuration.php +++ b/app/Livewire/Settings/Configuration.php @@ -15,6 +15,7 @@ class Configuration extends Component public bool $do_not_track; public bool $is_auto_update_enabled; public bool $is_registration_enabled; + public bool $is_dns_validation_enabled; public bool $next_channel; protected string $dynamic_config_path = '/data/coolify/proxy/dynamic'; protected Server $server; @@ -24,12 +25,14 @@ class Configuration extends Component 'settings.resale_license' => 'nullable', 'settings.public_port_min' => 'required', 'settings.public_port_max' => 'required', + 'settings.custom_dns_servers' => 'nullable', ]; protected $validationAttributes = [ 'settings.fqdn' => 'FQDN', 'settings.resale_license' => 'Resale License', 'settings.public_port_min' => 'Public port min', 'settings.public_port_max' => 'Public port max', + 'settings.custom_dns_servers' => 'Custom DNS servers', ]; public function mount() @@ -38,6 +41,7 @@ public function mount() $this->is_auto_update_enabled = $this->settings->is_auto_update_enabled; $this->is_registration_enabled = $this->settings->is_registration_enabled; $this->next_channel = $this->settings->next_channel; + $this->is_dns_validation_enabled = $this->settings->is_dns_validation_enabled; } public function instantSave() @@ -45,6 +49,7 @@ public function instantSave() $this->settings->do_not_track = $this->do_not_track; $this->settings->is_auto_update_enabled = $this->is_auto_update_enabled; $this->settings->is_registration_enabled = $this->is_registration_enabled; + $this->settings->is_dns_validation_enabled = $this->is_dns_validation_enabled; if ($this->next_channel) { $this->settings->next_channel = false; $this->next_channel = false; @@ -63,6 +68,14 @@ public function submit() return; } $this->validate(); + + $this->settings->custom_dns_servers = str($this->settings->custom_dns_servers)->replaceEnd(',', '')->trim(); + $this->settings->custom_dns_servers = str($this->settings->custom_dns_servers)->trim()->explode(',')->map(function ($dns) { + return str($dns)->trim()->lower(); + }); + $this->settings->custom_dns_servers = $this->settings->custom_dns_servers->unique(); + $this->settings->custom_dns_servers = $this->settings->custom_dns_servers->implode(','); + $this->settings->save(); $this->server = Server::findOrFail(0); $this->setup_instance_fqdn(); diff --git a/bootstrap/helpers/proxy.php b/bootstrap/helpers/proxy.php index 1c419afbf..80eebe1a6 100644 --- a/bootstrap/helpers/proxy.php +++ b/bootstrap/helpers/proxy.php @@ -288,7 +288,7 @@ function setup_dynamic_configuration() ], $server); if (config('app.env') == 'local') { - ray($yaml); + // ray($yaml); } } } diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index 87a850fe4..ce51745db 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -22,14 +22,11 @@ use App\Notifications\Channels\TelegramChannel; use App\Notifications\Internal\GeneralNotification; use DanHarrin\LivewireRateLimiting\Exceptions\TooManyRequestsException; -use Illuminate\Database\QueryException; use Illuminate\Mail\Message; use Illuminate\Notifications\Messages\MailMessage; -use Illuminate\Support\Collection; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\Http; -use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Request; use Illuminate\Support\Facades\Route; @@ -40,6 +37,7 @@ use phpseclib3\Crypt\RSA; use Spatie\Url\Url; use Symfony\Component\Yaml\Yaml; +use PurplePixie\PhpDns\DNSQuery; function base_configuration_dir(): string { @@ -1592,3 +1590,50 @@ function getRealtime() return $envDefined; } } + +function validate_dns_entry(string $fqdn, Server $server) +{ + $url = Url::fromString($fqdn); + $host = $url->getHost(); + if (str($host)->contains('sslip.io')) { + return true; + } + $settings = InstanceSettings::get(); + $is_dns_validation_enabled = data_get($settings, 'is_dns_validation_enabled'); + if (!$is_dns_validation_enabled) { + return true; + } + $dnsServers = data_get($settings, 'custom_dns_servers'); + $dnsServers = str($dnsServers)->explode(','); + if ($server->id === 0) { + $ip = data_get($settings, 'public_ipv4') || data_get($settings, 'public_ipv6') || $server->ip; + } else { + $ip = $server->ip; + } + $foundMatch = false; + $type = \PurplePixie\PhpDns\DNSTypes::NAME_A; + foreach ($dnsServers as $dnsServer) { + try { + ray("Checking $host on $dnsServer"); + $query = new DNSQuery($dnsServer); + $results = $query->query($host, $type); + if ($results === false || $query->hasError()) { + ray("Error: " . $query->getLasterror()); + } else { + foreach ($results as $result) { + if ($result->getType() == $type) { + if ($result->getData() === $ip) { + ray($host . " has IP address " . $result->getData()); + ray($result->getString()); + $foundMatch = true; + break; + } + } + } + } + } catch (\Exception $e) { + } + } + ray("Found match: $foundMatch"); + return $foundMatch; +} diff --git a/composer.json b/composer.json index 5a7f39844..e9cf53d10 100644 --- a/composer.json +++ b/composer.json @@ -28,6 +28,7 @@ "nubs/random-name-generator": "^2.2", "phpseclib/phpseclib": "~3.0", "poliander/cron": "^3.0", + "purplepixie/phpdns": "^2.1", "pusher/pusher-php-server": "^7.2", "resend/resend-laravel": "^0.5.0", "sentry/sentry-laravel": "^3.4", diff --git a/composer.lock b/composer.lock index 82bed2c82..8d0e9da81 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "44337ff4ff1d9c435d9776fec01ebe9c", + "content-hash": "de3b59fade9b132d2582a40dcf3c00f9", "packages": [ { "name": "amphp/amp", @@ -6287,6 +6287,54 @@ }, "time": "2023-10-14T21:56:36+00:00" }, + { + "name": "purplepixie/phpdns", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/purplepixie/phpdns.git", + "reference": "e1e4f18a60d01947e2aac7157325a9e2e7755bf7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/purplepixie/phpdns/zipball/e1e4f18a60d01947e2aac7157325a9e2e7755bf7", + "reference": "e1e4f18a60d01947e2aac7157325a9e2e7755bf7", + "shasum": "" + }, + "require": { + "php": ">=7.4" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-0": { + "PurplePixie": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Cutting", + "email": "dcutting@purplepixie.org" + } + ], + "description": "PHP DNS Direct Query Module", + "support": { + "issues": "https://github.com/purplepixie/phpdns/issues", + "source": "https://github.com/purplepixie/phpdns/tree/2.1.0" + }, + "time": "2023-11-06T15:37:19+00:00" + }, { "name": "pusher/pusher-php-server", "version": "7.2.4", diff --git a/database/migrations/2024_01_15_084609_add_custom_dns_server.php b/database/migrations/2024_01_15_084609_add_custom_dns_server.php new file mode 100644 index 000000000..24d288d02 --- /dev/null +++ b/database/migrations/2024_01_15_084609_add_custom_dns_server.php @@ -0,0 +1,30 @@ +boolean('is_dns_validation_enabled')->default(true); + $table->string('custom_dns_servers')->nullable()->default('1.1.1.1'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('instance_settings', function (Blueprint $table) { + $table->dropColumn('is_dns_validation_enabled'); + $table->dropColumn('custom_dns_servers'); + }); + } +}; diff --git a/resources/views/livewire/settings/configuration.blade.php b/resources/views/livewire/settings/configuration.blade.php index 4abdbf600..091a07dbb 100644 --- a/resources/views/livewire/settings/configuration.blade.php +++ b/resources/views/livewire/settings/configuration.blade.php @@ -9,8 +9,10 @@
General configuration for your Coolify instance.
-
+
+ +
{{--