From e4bbc1def62cb22f4c0f223da3419cf61a1a401a Mon Sep 17 00:00:00 2001
From: Michael <github@michaelplas.de>
Date: Sat, 9 Sep 2023 23:47:21 +0200
Subject: [PATCH] See https://core.trac.wordpress.org/ticket/56141

---
 src/wp-admin/setup-config.php | 26 +++++++++++++++----
 src/wp-includes/functions.php | 47 +++++++++++++++++++++++++++++++++++
 2 files changed, 68 insertions(+), 5 deletions(-)

diff --git a/src/wp-admin/setup-config.php b/src/wp-admin/setup-config.php
index ddcb4943c7..8a8603e84b 100644
--- a/src/wp-admin/setup-config.php
+++ b/src/wp-admin/setup-config.php
@@ -410,20 +410,36 @@ switch ( $step ) {
 		}
 		unset( $line );
 
-		if ( ! is_writable( ABSPATH ) ) :
+		$dbhost_is_in_private_network = wp_is_dbhost_in_private_network( $dbhost );
+
+		if ( ! is_writable( ABSPATH ) || !$dbhost_is_in_private_network  ) :
 			setup_config_display_header();
 			?>
 <p>
 			<?php
-			/* translators: %s: wp-config.php */
-			printf( __( 'Unable to write to %s file.' ), '<code>wp-config.php</code>' );
+			if(!$dbhost_is_in_private_network){
+				//* translators: 1: Database Host, 2: wp-config.php. */
+				printf( __( 'Your database host %s is not part of a private network. For security reasons WordPress can not save the %s file automatically.' ), $dbhost, '<code>wp-config.php</code>' );
+			}
+
+			if(! is_writable( ABSPATH )){
+				/* translators: %s: wp-config.php */
+				printf( __( 'Unable to write to %s file.' ), '<code>wp-config.php</code>' );
+			}
 			?>
 </p>
 <p id="wp-config-description">
 			<?php
 			/* translators: %s: wp-config.php */
-			printf( __( 'You can create the %s file manually and paste the following text into it.' ), '<code>wp-config.php</code>' );
-
+			printf( __( 'You can create the %s file manually and paste the following text into it. ' ), '<code>wp-config.php</code>' );
+
+			printf(
+				/* translators: 1: Documentation URL, 2: wp-config.php */
+				__( 'Need more help? <a href="%1$s">Read the support article on %2$s</a>.' ),
+				__( 'https://wordpress.org/documentation/article/editing-wp-config-php/' ),
+				'<code>wp-config.php</code>'
+			);
+		
 			$config_text = '';
 
 			foreach ( $config_file as $line ) {
diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php
index 4a2a2b1779..9d4a7f2571 100644
--- a/src/wp-includes/functions.php
+++ b/src/wp-includes/functions.php
@@ -8754,3 +8754,50 @@ function is_php_version_compatible( $required ) {
 function wp_fuzzy_number_match( $expected, $actual, $precision = 1 ) {
 	return abs( (float) $expected - (float) $actual ) <= $precision;
 }
+
+/**
+ * Checks if the given dbhost is part of Private Adress Spaces rfc1918
+ *
+ * Converts the DB Host IP into long integer and compares with the given private networks.
+ * Additional networks can by specifying an environment variable `WP_ALLOWED_DBNETWORK`
+ *
+ * @since 6.5.0
+ * 
+ * @param string $dbhost IP or Hostname for DB Host
+ * @return bool Wheater is in private network or not
+ */
+function wp_is_dbhost_in_private_network( $dbhost ) {
+	$private_networks = array( 
+		"127.0.0.0/8",
+		"10.0.0.0/8",
+		"172.16.0.0/12",
+		"192.168.0.0/16"
+	);
+
+	// Check if `getenv` is available on the system, if the environment variable has been set and looks like a IP with subnetmask
+	if ( function_exists( 'getenv' ) && getenv( 'WP_ALLOWED_DBNETWORK' ) ) {
+		$pattern = '/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\/(\d{1,2})$/';
+		$allowed_network = getenv( 'WP_ALLOWED_DBNETWORK' );
+
+		if (preg_match($pattern, $allowed_network)) {
+			$private_networks[] = getenv( 'WP_ALLOWED_DBNETWORK' );
+		}
+	}
+
+	// Check if DB Host is a IP or if not get IP by hostname
+	$dbhostip = filter_var($dbhost, FILTER_VALIDATE_IP) ? $dbhost : gethostbyname($dbhost);
+
+	$ip_long = ip2long($dbhostip);
+	foreach ($private_networks as $network) {
+		list($subnetIP, $subnetMask) = explode('/', $network);
+		$subnetStartLong = ip2long($subnetIP);
+		$subnetMaskLong = -1 << (32 - $subnetMask);
+
+		// Check if the target IP is within the subnet
+		if (($ip_long & $subnetMaskLong) === ($subnetStartLong & $subnetMaskLong)) {
+    		return true; // IP address is in a private network
+        }
+    }
+
+    return false; // IP address is not in any of the private networks
+}
\ No newline at end of file
-- 
2.30.0.windows.2

