[PATCH v2 0/3] esx: Form URLs containing IPv6 addresses correctly
v1: https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/thread/YRCX4... In v2, replace multiple VIR_DEBUG with just one, and add the Reported-by and Reviewed-by tags on the last commit. I'm sure this can't be the only place in libvirt that has to solve this problem (nor the "is this hostname IPv6" problem for that matter), but my searching skills are not good enough to find any other places. Rich.
Signed-off-by: Richard W.M. Jones <rjones@redhat.com> --- src/esx/esx_vi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c index 3264afc13a..8d2ffb3f8f 100644 --- a/src/esx/esx_vi.c +++ b/src/esx/esx_vi.c @@ -231,6 +231,8 @@ esxVI_CURL_Perform(esxVI_CURL *curl, const char *url) long responseCode = 0; const char *redirectUrl = NULL; + VIR_DEBUG("URL: %s", url); + errorCode = curl_easy_perform(curl->handle); if (errorCode != CURLE_OK) { -- 2.52.0
Abstract the places where we create URLs into one place (but actually into two functions because of how URLs are used). Signed-off-by: Richard W.M. Jones <rjones@redhat.com> --- src/esx/esx_driver.c | 55 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 02f30c2b19..8d7c58c88f 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -582,7 +582,39 @@ esxCapsInit(esxPrivate *priv) return NULL; } +static char * +esxCreateURL(const char *transport, + const char *server, + int port, + const char *path) +{ + char *url; + url = g_strdup_printf("%s://%s:%d/%s", + transport, + server, + port, + path); + return url; +} + +static void +esxCreateURLBuffer(virBuffer *buffer, + const char *transport, + const char *server, + int port, + const char *path) +{ + /* Same as above, but add it to a buffer because the calling code + * will append query strings etc. + */ + virBufferAsprintf(buffer, + "%s://%s:%d/%s", + transport, + server, + port, + path); +} static int esxConnectToHost(esxPrivate *priv, @@ -619,8 +651,8 @@ esxConnectToHost(esxPrivate *priv, conn->uri->server))) goto cleanup; - url = g_strdup_printf("%s://%s:%d/sdk", priv->parsedUri->transport, - conn->uri->server, conn->uri->port); + url = esxCreateURL(priv->parsedUri->transport, + conn->uri->server, conn->uri->port, "sdk"); if (esxVI_Context_Alloc(&priv->host) < 0 || esxVI_Context_Connect(priv->host, url, ipAddress, username, password, @@ -706,8 +738,8 @@ esxConnectToVCenter(esxPrivate *priv, if (!(password = virAuthGetPassword(conn, auth, "esx", username, hostname))) return -1; - url = g_strdup_printf("%s://%s:%d/sdk", priv->parsedUri->transport, hostname, - conn->uri->port); + url = esxCreateURL(priv->parsedUri->transport, hostname, + conn->uri->port, "sdk"); if (esxVI_Context_Alloc(&priv->vCenter) < 0 || esxVI_Context_Connect(priv->vCenter, url, ipAddress, username, @@ -2357,8 +2389,9 @@ esxDomainScreenshot(virDomainPtr domain, virStreamPtr stream, } /* Build URL */ - virBufferAsprintf(&buffer, "%s://%s:%d/screen?id=", priv->parsedUri->transport, - domain->conn->uri->server, domain->conn->uri->port); + esxCreateURLBuffer(&buffer, priv->parsedUri->transport, + domain->conn->uri->server, domain->conn->uri->port, + "screen?id="); virBufferURIEncodeString(&buffer, virtualMachine->obj->value); url = virBufferContentAndReset(&buffer); @@ -2563,8 +2596,9 @@ esxDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) goto cleanup; } - virBufferAsprintf(&buffer, "%s://%s:%d/folder/", priv->parsedUri->transport, - domain->conn->uri->server, domain->conn->uri->port); + esxCreateURLBuffer(&buffer, priv->parsedUri->transport, + domain->conn->uri->server, domain->conn->uri->port, + "folder/"); virBufferURIEncodeString(&buffer, directoryAndFileName); virBufferAddLit(&buffer, "?dcPath="); esxUtil_EscapeInventoryObject(&buffer, priv->primary->datacenterPath); @@ -2987,8 +3021,9 @@ esxDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags) goto cleanup; } - virBufferAsprintf(&buffer, "%s://%s:%d/folder/", priv->parsedUri->transport, - conn->uri->server, conn->uri->port); + esxCreateURLBuffer(&buffer, priv->parsedUri->transport, + conn->uri->server, conn->uri->port, + "folder/"); if (directoryName) { virBufferURIEncodeString(&buffer, directoryName); -- 2.52.0
When creating a URL to pass to curl, if the server name is an IPv6 address, enclose it in '[...]', for example forming a URL like: https://[1234:56:0:789a:bcde:72ff:fe0a:7baa]:443/sdk Fixes: https://issues.redhat.com/browse/RHEL-138300 Updates: commit 845210011a9ffd9d17e30c51cbc81ba67c5d3166 Reported-by: Ming Xie <mxie@redhat.com> Signed-off-by: Richard W.M. Jones <rjones@redhat.com> Reviewed-by: Michal Privoznik <mprivozn@redhat.com> --- src/esx/esx_driver.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 8d7c58c88f..208077eeda 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -582,6 +582,19 @@ esxCapsInit(esxPrivate *priv) return NULL; } +static bool +esxServerIsIPv6(const char *server) +{ + size_t i; + const size_t n = strlen(server); + + for (i = 0; i < n; ++i) { + if (!g_ascii_isxdigit(server[i]) && server[i] != ':') + return false; + } + return true; +} + static char * esxCreateURL(const char *transport, const char *server, @@ -589,10 +602,13 @@ esxCreateURL(const char *transport, const char *path) { char *url; + const bool is_ipv6 = esxServerIsIPv6(server); - url = g_strdup_printf("%s://%s:%d/%s", + url = g_strdup_printf("%s://%s%s%s:%d/%s", transport, + is_ipv6 ? "[" : "", server, + is_ipv6 ? "]" : "", port, path); return url; @@ -605,13 +621,17 @@ esxCreateURLBuffer(virBuffer *buffer, int port, const char *path) { + const bool is_ipv6 = esxServerIsIPv6(server); + /* Same as above, but add it to a buffer because the calling code * will append query strings etc. */ virBufferAsprintf(buffer, - "%s://%s:%d/%s", + "%s://%s%s%s:%d/%s", transport, + is_ipv6 ? "[" : "", server, + is_ipv6 ? "]" : "", port, path); } -- 2.52.0
On 1/26/26 15:22, Richard W.M. Jones wrote:
v1: https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/thread/YRCX4...
In v2, replace multiple VIR_DEBUG with just one, and add the Reported-by and Reviewed-by tags on the last commit.
I'm sure this can't be the only place in libvirt that has to solve this problem (nor the "is this hostname IPv6" problem for that matter), but my searching skills are not good enough to find any other places.
Thing is, it can be not just address but a hostname too. I mean we do have virSocketAddrFormat() but that works specifically with IP addresses and/or UNIX sockets. And in this case, the hostname can be "123.datacentre.internal.company.org" or whatever. Having said that, esxUtil_ResolveHostname() returns resolved IP address and it is passed to esxVI_Context_Connect() indeed, but HTTP has this 'Host' header field where the original hostname should appear, not resolved IP address (though, I don't think anybody is running a web server on their VMWare hosts). Reviewed-by: Michal Privoznik <mprivozn@redhat.com> Michal
On Mon, Jan 26, 2026 at 04:01:44PM +0100, Michal Prívozník via Devel wrote:
On 1/26/26 15:22, Richard W.M. Jones wrote:
v1: https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/thread/YRCX4...
In v2, replace multiple VIR_DEBUG with just one, and add the Reported-by and Reviewed-by tags on the last commit.
I'm sure this can't be the only place in libvirt that has to solve this problem (nor the "is this hostname IPv6" problem for that matter), but my searching skills are not good enough to find any other places.
Thing is, it can be not just address but a hostname too. I mean we do have virSocketAddrFormat() but that works specifically with IP addresses and/or UNIX sockets. And in this case, the hostname can be "123.datacentre.internal.company.org" or whatever.
Having said that, esxUtil_ResolveHostname() returns resolved IP address and it is passed to esxVI_Context_Connect() indeed, but HTTP has this 'Host' header field where the original hostname should appear, not resolved IP address (though, I don't think anybody is running a web server on their VMWare hosts).
Can we use virURI for ESX URI formatting ? That didn't try to detect IPv6 formally, but instead simply adds [] if the "server name" contained a ":".
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
Michal
With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
On Mon, Jan 26, 2026 at 03:11:42PM +0000, Daniel P. Berrangé wrote:
On Mon, Jan 26, 2026 at 04:01:44PM +0100, Michal Prívozník via Devel wrote:
On 1/26/26 15:22, Richard W.M. Jones wrote:
v1: https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/thread/YRCX4...
In v2, replace multiple VIR_DEBUG with just one, and add the Reported-by and Reviewed-by tags on the last commit.
I'm sure this can't be the only place in libvirt that has to solve this problem (nor the "is this hostname IPv6" problem for that matter), but my searching skills are not good enough to find any other places.
Thing is, it can be not just address but a hostname too. I mean we do have virSocketAddrFormat() but that works specifically with IP addresses and/or UNIX sockets. And in this case, the hostname can be "123.datacentre.internal.company.org" or whatever.
Having said that, esxUtil_ResolveHostname() returns resolved IP address and it is passed to esxVI_Context_Connect() indeed, but HTTP has this 'Host' header field where the original hostname should appear, not resolved IP address (though, I don't think anybody is running a web server on their VMWare hosts).
Can we use virURI for ESX URI formatting ? That didn't try to detect IPv6 formally, but instead simply adds [] if the "server name" contained a ":".
Indeed it does. I'll see if we can use src/utils/viruri.c. Rich.
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
Michal
With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
-- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-p2v converts physical machines to virtual machines. Boot with a live CD or over the network (PXE) and turn machines into KVM guests. http://libguestfs.org/virt-v2v
participants (3)
-
Daniel P. Berrangé -
Michal Prívozník -
Richard W.M. Jones