Default to system IPv4/IPv6 preference when resolving hostnames

Fixes #667. This implementation is similar but also preserves compatibility with the "ipv6" option,
which allows setting the preferred address type without hardcoding a bind IP.
This commit is contained in:
James Lu 2021-12-25 00:16:26 -08:00
parent f55057092a
commit ac7339e460
2 changed files with 25 additions and 24 deletions

View File

@ -1857,30 +1857,34 @@ class IRCNetwork(PyLinkNetworkCoreWithUtils):
"""
self._pre_connect()
ip = self.serverdata["ip"]
remote = self.serverdata["ip"]
port = self.serverdata["port"]
try:
# Set the socket type (IPv6 or IPv4), auto detecting it if not specified.
isipv6 = self.serverdata.get("ipv6", utils.get_hostname_type(ip) == 2)
if 'bindhost' in self.serverdata:
# Try detecting the socket type from the bindhost if specified.
force_ipv6 = utils.get_hostname_type(self.serverdata['bindhost']) == 2
else:
force_ipv6 = self.serverdata.get("ipv6") # ternary value (None = use system default)
if (not isipv6) and 'bindhost' in self.serverdata:
# Also try detecting the socket type from the bindhost if specified.
isipv6 = utils.get_hostname_type(self.serverdata['bindhost']) == 2
if force_ipv6 is True:
dns_stype = socket.AF_INET6
elif force_ipv6 is False:
dns_stype = socket.AF_INET
else:
dns_stype = socket.AF_UNSPEC
stype = socket.AF_INET6 if isipv6 else socket.AF_INET
dns_result = socket.getaddrinfo(remote, port, family=dns_stype)[0]
ip = dns_result[-1][0]
# Creat the socket.
self._socket = socket.socket(stype)
log.debug('(%s) Resolving address %s to %s (force_ipv6=%s)', self.name, remote, ip, force_ipv6)
# Create the actual socket.
self._socket = socket.socket(dns_result[0])
# Set the socket bind if applicable.
if 'bindhost' in self.serverdata:
self._socket.bind((self.serverdata['bindhost'], 0))
# Resolve hostnames if it's not an IP address already.
old_ip = ip
ip = socket.getaddrinfo(ip, port, stype)[0][-1][0]
log.debug('(%s) Resolving address %s to %s', self.name, old_ip, ip)
# Enable SSL if set to do so.
self.ssl = self.serverdata.get('ssl')
if self.ssl:

View File

@ -305,13 +305,6 @@ servers:
ip: ::1
port: 8067
# Determines whether IPv6 should be used for this connection. Should the ip:
# above be a hostname instead of an IP, this will also affect whether A records
# (IPv4) or AAAA records (IPv6) will be used in resolving it.
# As of PyLink 2.0-beta1, you can leave this unset for direct connections to IP addresses;
# the address type will be automatically detected.
#ipv6: yes
# Received and sent passwords. For passwordless links using SSL fingerprints, simply set
# these two fields to "*" and enable SSL with a cert and key file.
recvpass: "coffee"
@ -345,9 +338,13 @@ servers:
port: 45454
# When the IP field is set to a hostname, the "ipv6" option determines whether IPv4 or IPv6
# addresses should be used when resolving it. You can leave this field blank and use an
# explicit bindhost instead, which will let the the address type be automatically detected.
#ipv6: false
# addresses should be used when resolving it.
# As of PyLink 3.1, this defaults to null, falling back to the system's default preferences
# if not set (e.g. /etc/gai.conf on Linux). Previous versions default to making IPv4 connections only.
# This option is overridden by "bindhost" if it is also provided.
#ipv6: null
# Specifies the IP to make outgoing connections from, for multi-homed hosts.
#bindhost: 1111:2222:3333:4444
# Note: if you are actually using dynamic DNS for an IRC link, consider enabling