From d53ece48cbf511aece8c7e5fb9b17e0ae395ffbf Mon Sep 17 00:00:00 2001 From: Jose Domenech Date: Thu, 5 Feb 2026 14:38:32 +0100 Subject: [PATCH] Fix IPv6 hostname resolution and literal handling in API URLs --- pve2_api.class.php | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/pve2_api.class.php b/pve2_api.class.php index 021a07c..40b5879 100755 --- a/pve2_api.class.php +++ b/pve2_api.class.php @@ -43,7 +43,10 @@ public function __construct ($hostname, $username, $realm, $password, $port = 80 } // Check hostname resolves. if (gethostbyname($hostname) == $hostname && !filter_var($hostname, FILTER_VALIDATE_IP)) { - throw new PVE2_Exception("Cannot resolve {$hostname}.", 2); + // Fallback: check for IPv6 (AAAA) records if IPv4 lookup failed + if (!checkdnsrr($hostname, 'AAAA')) { + throw new PVE2_Exception("Cannot resolve {$hostname}.", 2); + } } // Check port is between 1 and 65535. if (!filter_var($port, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 65535]])) { @@ -78,7 +81,13 @@ public function login () { // Perform login request. $prox_ch = curl_init(); - curl_setopt($prox_ch, CURLOPT_URL, "https://{$this->hostname}:{$this->port}/api2/json/access/ticket"); + + // Handle IPv6 literals in URL + $host_url = $this->hostname; + if (filter_var($this->hostname, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { + $host_url = '[' . $this->hostname . ']'; + } + curl_setopt($prox_ch, CURLOPT_URL, "https://{$host_url}:{$this->port}/api2/json/access/ticket"); curl_setopt($prox_ch, CURLOPT_POST, true); curl_setopt($prox_ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($prox_ch, CURLOPT_POSTFIELDS, $login_postfields_string); @@ -168,7 +177,13 @@ private function action ($action_path, $http_method, $put_post_parameters = null // Prepare cURL resource. $prox_ch = curl_init(); - curl_setopt($prox_ch, CURLOPT_URL, "https://{$this->hostname}:{$this->port}/api2/json{$action_path}"); + + // Handle IPv6 literals in URL + $host_url = $this->hostname; + if (filter_var($this->hostname, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { + $host_url = '[' . $this->hostname . ']'; + } + curl_setopt($prox_ch, CURLOPT_URL, "https://{$host_url}:{$this->port}/api2/json{$action_path}"); $put_post_http_headers = array(); $put_post_http_headers[] = "CSRFPreventionToken: {$this->login_ticket['CSRFPreventionToken']}";