[libvirt] [PATCH 2/2] Bind to both IPv4 and v6 when checking port availability
Daniel P. Berrange
berrange at redhat.com
Tue Oct 1 09:19:05 UTC 2013
On Tue, Oct 01, 2013 at 11:01:37AM +0200, Ján Tomko wrote:
> If IPv6 is enabled on the host, bind to :: with IPV6_V6ONLY disabled
> to check for ports available on both IPv6 and IPv4.
> ---
> src/util/virportallocator.c | 34 +++++++++++++++++++++++++++-------
> 1 file changed, 27 insertions(+), 7 deletions(-)
>
> diff --git a/src/util/virportallocator.c b/src/util/virportallocator.c
> index 5b7ad41..246f6cd 100644
> --- a/src/util/virportallocator.c
> +++ b/src/util/virportallocator.c
> @@ -99,14 +99,25 @@ int virPortAllocatorAcquire(virPortAllocatorPtr pa,
> int ret = -1;
> size_t i;
> int fd = -1;
> + bool ipv6 = virHostHasIPv6();
>
> *port = 0;
> virObjectLock(pa);
>
> for (i = pa->start; i <= pa->end && !*port; i++) {
> - int reuse = 1;
> - struct sockaddr_in addr;
> + int reuse = 1, v6only = 0;
> + struct sockaddr_in addr = {
> + .sin_family = AF_INET,
> + .sin_port = htons(i),
> + .sin_addr.s_addr = htonl(INADDR_ANY)
> + };
> + struct sockaddr_in6 addr6 = {
> + .sin6_family = AF_INET6,
> + .sin6_port = htons(i),
> + .sin6_addr = IN6ADDR_ANY_INIT
> + };
> bool used = false;
> + int rc;
>
> if (virBitmapGetBit(pa->bitmap,
> i - pa->start, &used) < 0) {
> @@ -118,10 +129,7 @@ int virPortAllocatorAcquire(virPortAllocatorPtr pa,
> if (used)
> continue;
>
> - addr.sin_family = AF_INET;
> - addr.sin_port = htons(i);
> - addr.sin_addr.s_addr = htonl(INADDR_ANY);
> - fd = socket(PF_INET, SOCK_STREAM, 0);
> + fd = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_STREAM, 0);
> if (fd < 0) {
> virReportSystemError(errno, "%s",
> _("Unable to open test socket"));
> @@ -134,7 +142,19 @@ int virPortAllocatorAcquire(virPortAllocatorPtr pa,
> goto cleanup;
> }
>
> - if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
> + if (ipv6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&v6only,
> + sizeof(v6only)) < 0) {
> + virReportSystemError(errno, "%s",
> + _("Unable to unset socket IPV6_V6ONLY flag"));
> + goto cleanup;
> + }
> +
> + if (ipv6)
> + rc = bind(fd, (struct sockaddr*)&addr6, sizeof(addr6));
> + else
> + rc = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
IMHO you could write this code without needing to have any upfront check
for whether IPv6 is enabled. Set IPV6_V6ONLY == 1.
Then unconditionally try to bind separately on IPv4, and IPv6, and catch
the error you'd get back if either IPv4 or IPv6 were disabled on the
host.
Regards,
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
More information about the libvir-list
mailing list