diff options
author | Martin Kosek <mkosek@redhat.com> | 2012-07-03 16:49:10 +0200 |
---|---|---|
committer | Martin Kosek <mkosek@redhat.com> | 2012-07-13 14:25:18 +0200 |
commit | 4879c68d68634715b9d08a08a4c7be882634409f (patch) | |
tree | f64ca647665df5b40fb5501735d7bb5a9776786c /ipa-client/ipa-install | |
parent | 5c54dd5b03681428040af51ef3e05c10bec91d3f (diff) | |
download | freeipa-4879c68d68634715b9d08a08a4c7be882634409f.tar.gz freeipa-4879c68d68634715b9d08a08a4c7be882634409f.tar.xz freeipa-4879c68d68634715b9d08a08a4c7be882634409f.zip |
Improve address family handling in sockets
Many functions use low-level socket interface for connection or
various checks. However, most of the time we don't respect
automatic address family detection but rather try to force our
values. This may cause either redundat connection tries when an
address family is disabled on system tries or even crashes
when socket exceptions are not properly caught.
Instead of forcing address families to socket, rather use
getaddrinfo interface to automatically retrieve a list of all
relevant address families and other connection settings when
connecting to remote/local machine or binding to a local port.
Now, we will also fill correctly all connection parameters like
flowinfo and scopeid for IPv6 connections which will for example
prevent issues with scoped IPv6 addresses.
bind_port_responder function was changed to at first try to bind
to IPv6 wildcard address before IPv4 as IPv6 socket is able to
accept both IPv4 and IPv6 connections (unlike IPv4 socket).
nsslib connection was refactored to use nss.io.AddrInfo class to
get all the available connections. Socket is now not created by
default in NSSConnection class initializer, but rather when the
actual connection is being made, becase we do not an address family
where connection is successful.
https://fedorahosted.org/freeipa/ticket/2913
https://fedorahosted.org/freeipa/ticket/2695
Diffstat (limited to 'ipa-client/ipa-install')
-rwxr-xr-x | ipa-client/ipa-install/ipa-client-install | 49 |
1 files changed, 36 insertions, 13 deletions
diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install index ef0dc293c..081ae7f28 100755 --- a/ipa-client/ipa-install/ipa-client-install +++ b/ipa-client/ipa-install/ipa-client-install @@ -979,19 +979,36 @@ def configure_ssh(fstore, ssh_dir, options): def resolve_ipaddress(server): """ Connect to the server's LDAP port in order to determine what ip address this machine uses as "public" ip (relative to the server). + + Returns a tuple with the IP address and address family when + connection was successful. Socket error is raised otherwise. """ + last_socket_error = None - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP) - try: - s.connect((server, 389)) - addr, port = s.getsockname() - except socket.gaierror: - s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM, socket.IPPROTO_TCP) - s.connect((server, 389)) - addr, port, foo, bar = s.getsockname() - s.close() + for res in socket.getaddrinfo(server, 389, socket.AF_UNSPEC, + socket.SOCK_STREAM): + af, socktype, proto, canonname, sa = res + try: + s = socket.socket(af, socktype, proto) + except socket.error, e: + last_socket_error = e + s = None + continue + + try: + s.connect(sa) + sockname = s.getsockname() + + # For both IPv4 and IPv6 own IP address is always the first item + return (sockname[0], af) + except socket.error, e: + last_socket_error = e + finally: + if s: + s.close() - return addr + if last_socket_error is not None: + raise last_socket_error # pylint: disable=E0702 def do_nsupdate(update_txt): root_logger.debug("Writing nsupdate commands to %s:", UPDATE_FILE) @@ -1037,7 +1054,13 @@ CCACHE_FILE = "/etc/ipa/.dns_ccache" def update_dns(server, hostname): - ip = resolve_ipaddress(server) + try: + (ip, af) = resolve_ipaddress(server) + except socket.gaierror, e: + root_logger.debug("update_dns: could not connect to server: %s", e) + root_logger.error("Cannot update DNS records! " + "Failed to connect to server '%s'.", server) + return sub_dict = dict(HOSTNAME=hostname, IPADDRESS=ip, @@ -1045,9 +1068,9 @@ def update_dns(server, hostname): ZONE='.'.join(hostname.split('.')[1:]) ) - if len(ip.split('.')) == 4: + if af == socket.AF_INET: template = UPDATE_TEMPLATE_A - elif ':' in ip: + elif af == socket.AF_INET6: template = UPDATE_TEMPLATE_AAAA else: root_logger.info("Failed to determine this machine's ip address.") |