IPv6 in HTCondor, a developer's perspective

See also HowToEnableIpvSix .

The Rules

The Big Picture

condor_sockaddr

/src/condor_includes/condor_sockaddr.h

The data structure holding information about a IP address/port pair is condor_sockaddr, which handles juggling sockaddr_in and sockaddr_in6. You shouldn't worry if a given address is IPv6 or IPv4, just use the condor_sockaddr opaquely. If you need a textual but still opaque representation, use condor_sockaddr::to_sinful and condor_sockaddr::from_sinful to create and parse sinful strings. Sinful string are human readable and thus appropriate to use in log messages.

IPv6 addresses require a scope id, identifying which network interface to use. This solves the problem of a single machine being part of two or more private ("link local") networks using the same address space. However, it just creates a new problem: if all you have is an IP address, how do you know which interface to use. The answer: we have no idea. Some tools allow the user to specify the scope ID in a variety of inconsistent ways. This is why NETWORK_INTERFACE is required for IPv6; we use the NETWORK_INTERFACE to identify the scope ID.

condor_netaddr

/src/condor_includes/condor_netaddr.h

condor_netaddr exists to encapsulate the idea of a subnet. It's built on top of condor_sockaddr, adding a count for how many bits to mask off. At the moment it's only being used to validate that a subset string can be parsed, but should eventually be used in any situation where HTCondor is checking that a given address is within a given subset (ie security).

Conversions

All conversions should go through condor_sockaddr. Since you should be using condor_sockaddr internally whenever possible, direct conversion (eg hostname to IP address as a string) should be rare enough that direct functions are unnecessary.

hostname to condor_sockaddr

resolve_hostname() in /src/condor_includes/ipv6_hostname.h takes a hostname (MyString or const char *), and returns a std::vector<condor_sockaddr>.

Note that all of the returned condor_sockaddrs are correct! To be properly behaved, you should try them, in order, until you find one that works, or you run out of options.

sinful string to condor_sockaddr

condor_sockaddr::from_sinful() in /src/condor_includes/condor_sockaddr.h

IP address (as a string) to condor_sockaddr

resolve_hostname() in /src/condor_includes/ipv6_hostname.h can transform IPv4 and IPv6 addresses into condor_sockaddrs as well as looking up hostnames. Use these. This can not parse attached ports, square brackets around an IPv6 address, nor IPv4 addresses in any form other than dotted decimal.

in_addr, in6_addr, sockaddr_in, or sockaddr_in6 to condor_sockaddr

You probably shouldn't have one of these in the first place. Assuming you started with a hostname, an IP address, or a sinful string, you should have gone straight to a condor_sockaddr. But if you absolutely must, condor_sockaddr's constructors can take these. /src/condor_includes/condor_sockaddr.h

condor_sockaddr to hostname

get_hostname() in /src/condor_includes/ipv6_hostname.h takes a condor_sockaddr and returns a hostname (MyString). If you want aliases as well, get_hostname_with_alias will return a std::vector<MyString> of hostnames.

condor_sockaddr to sinful string

condor_sockaddr::to_sinful() in /src/condor_includes/condor_sockaddr.h

condor_sockaddr to IP address (as a string)

You almost certainly don't want this. If you're looking for something to pass between daemons, perhaps in a ClassAd or on a command line, use a sinful string. If you're looking for something to put into a log or error message, still use a sinful string. While officially opaque, they are also designed to be human readable enough to be useful in log messages, and using the sinful string ensures that no information is lost. If you absolutely must (perhaps to pass it to a non-HTCondor program) use condor_sockaddr::to_ip_string() and condor_sockaddr::to_ip_string() in /src/condor_includes/condor_sockaddr.h

condor_sockaddr to sockaddr_in or sockaddr_in6

You almost certainly don't want this. Any function you want to call with a sockaddr_in or sockaddr_in6 probably has a condor_X equivalent that takes a condor_sockaddr; use that instead. For example instead of bind() and accept(), use condor_bind() and condor_accept(). If a condor_X equivalent doesn't exist, consider adding one. If you absolutely must, look to condor_sockaddr::is_ipv4() and condor_sockaddr::is_ipv6() to identify what type of address it is, and condor_sockaddr::to_sin() and condor_sockaddr::to_sin6() to retrieve sockaddr_in and sockaddr_in6 resepectively. /src/condor_includes/condor_sockaddr.h