[Hostlist] Support IPv6 in host lists

socket.gethostbyname does not support IPv6 name resolution, and
getaddrinfo() should be used instead for IPv4/v6 dual stack support.

Closes: https://github.com/deluge-torrent/deluge/pull/376
This commit is contained in:
tbkizle 2022-02-15 15:14:18 -05:00 committed by Calum Lind
parent 5f8acabb81
commit c89a366dfb
No known key found for this signature in database
GPG Key ID: 90597A687B836BA3
2 changed files with 30 additions and 25 deletions

View File

@ -8,7 +8,7 @@
import logging import logging
import os import os
from socket import gaierror, gethostbyname from socket import gaierror, getaddrinfo
from urllib.parse import urlparse from urllib.parse import urlparse
from gi.repository import Gtk from gi.repository import Gtk
@ -222,7 +222,7 @@ class ConnectionManager(component.Component):
__, host, port, __, __, status, __, __ = model[row] __, host, port, __, __, status, __, __ = model[row]
try: try:
gethostbyname(host) getaddrinfo(host, None)
except gaierror as ex: except gaierror as ex:
log.error( log.error(
'Error resolving host %s to ip: %s', row[HOSTLIST_COL_HOST], ex.args[1] 'Error resolving host %s to ip: %s', row[HOSTLIST_COL_HOST], ex.args[1]

View File

@ -9,7 +9,7 @@
import logging import logging
import os import os
import uuid import uuid
from socket import gaierror, gethostbyname from socket import gaierror, getaddrinfo
from twisted.internet import defer from twisted.internet import defer
@ -22,7 +22,7 @@ log = logging.getLogger(__name__)
DEFAULT_HOST = '127.0.0.1' DEFAULT_HOST = '127.0.0.1'
DEFAULT_PORT = 58846 DEFAULT_PORT = 58846
LOCALHOST = ('127.0.0.1', 'localhost') LOCALHOST = ('127.0.0.1', 'localhost', '::1')
def default_hostlist(): def default_hostlist():
@ -44,7 +44,7 @@ def validate_host_info(hostname, port):
""" """
try: try:
gethostbyname(hostname) getaddrinfo(hostname, None)
except gaierror as ex: except gaierror as ex:
raise ValueError('Host %s: %s', hostname, ex.args[1]) raise ValueError('Host %s: %s', hostname, ex.args[1])
@ -216,30 +216,35 @@ class HostList:
return defer.succeed(status_offline) return defer.succeed(status_offline)
try: try:
ip = gethostbyname(host) ips = list({addrinfo[4][0] for addrinfo in getaddrinfo(host, None)})
except gaierror as ex: except (gaierror, IndexError) as ex:
log.warning('Unable to resolve host %s to IP: %s', host, ex.args[1]) log.warning('Unable to resolve host %s to IP: %s', host, ex.args[1])
return defer.succeed(status_offline) return defer.succeed(status_offline)
host_conn_info = ( host_conn_list = [
ip, (
port, host_ip,
'localclient' if not user and host in LOCALHOST else user, port,
) 'localclient' if not user and host_ip in LOCALHOST else user,
if client.connected() and host_conn_info == client.connection_info(): )
# Currently connected to host_id daemon. for host_ip in ips
def on_info(info, host_id): ]
log.debug('Client connected, query info: %s', info)
return host_id, 'Connected', info
return client.daemon.info().addCallback(on_info, host_id) for host_conn_info in host_conn_list:
else: if client.connected() and host_conn_info == client.connection_info():
# Attempt to connect to daemon with host_id details. # Currently connected to host_id daemon.
c = Client() def on_info(info, host_id):
d = c.connect(host, port, skip_authentication=True) log.debug('Client connected, query info: %s', info)
d.addCallback(on_connect, c, host_id) return host_id, 'Connected', info
d.addErrback(on_connect_failed, host_id)
return d return client.daemon.info().addCallback(on_info, host_id)
else:
# Attempt to connect to daemon with host_id details.
c = Client()
d = c.connect(host, port, skip_authentication=True)
d.addCallback(on_connect, c, host_id)
d.addErrback(on_connect_failed, host_id)
return d
def update_host(self, host_id, hostname, port, username, password): def update_host(self, host_id, hostname, port, username, password):
"""Update the supplied host id with new connection details. """Update the supplied host id with new connection details.