Skip to content

Commit

Permalink
rewrite socket error handling, fixes #522
Browse files Browse the repository at this point in the history
socket.error is deprecated and is the same as OSError since python 3.3.
Of course OSError can mean a lot of stuff, so not sure how that goes...

socket.herror is for gethostbyaddr and has some documented h_error values in netdb.h
(but, AFAIK, these symbols are not available via python).

added a handler for h_error 0 (#522), which crashed since a while.
removed some unclear error values, let's see what happens.
  • Loading branch information
ThomasWaldmann committed Apr 18, 2023
1 parent 2bbec89 commit 2d8b44b
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 19 deletions.
42 changes: 24 additions & 18 deletions src/nsupdate/main/dnstools.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ def delete(fqdn, rdtype=None):
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
# no dns entry, it is already deleted
ok = False
except (dns.resolver.Timeout, dns.resolver.NoNameservers) as e: # socket.error also?
except (dns.resolver.Timeout, dns.resolver.NoNameservers) as e: # OSError (socket.error) also?
# maybe could be caused by secondary DNS Timeout and master still ok?
# assume the delete is OK...
ok = True
Expand Down Expand Up @@ -215,7 +215,7 @@ def update(fqdn, ipaddr, ttl=60):
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
# no dns entry yet, ok
ok = True
except (dns.resolver.Timeout, dns.resolver.NoNameservers) as e: # socket.error also?
except (dns.resolver.Timeout, dns.resolver.NoNameservers) as e: # OSError (socket.error) also?
# maybe could be caused by secondary DNS Timeout and master still ok?
# assume the update is OK...
ok = True
Expand Down Expand Up @@ -264,7 +264,7 @@ def query_ns(fqdn, rdtype, prefer_primary=False):
ip = str(list(answer)[0])
logger.debug("query: %s answer: %s" % (fqdn, ip))
return ip
except (dns.resolver.Timeout, dns.resolver.NoNameservers, dns.message.UnknownTSIGKey) as e: # socket.error also?
except (dns.resolver.Timeout, dns.resolver.NoNameservers, dns.message.UnknownTSIGKey) as e: # OSError (socket.error) also?
logger.warning("error when querying for name '%s' in zone '%s' with rdtype '%s' [%s]." % (
fqdn.host, origin, rdtype, str(e)))
set_ns_availability(origin, False)
Expand All @@ -279,6 +279,10 @@ def rev_lookup(ipaddr):
:param ipaddr: ip address (str)
:return: hostname (or empty string if lookup failed)
# define TRY_AGAIN 2 /* Non-Authoritative Host not found,
or SERVERFAIL. */
"""
if ipaddr:
retries = 4
Expand All @@ -287,18 +291,20 @@ def rev_lookup(ipaddr):
retries -= 1
try:
return socket.gethostbyaddr(ipaddr)[0]
except socket.error as err:
if err.errno in (-5, 4):
# -5 / 4 == no address associated with hostname (invalid ip?)
logger.warning("errno -5 when trying to reverse lookup %r" % ipaddr)
break
if err.errno in (errno.EPERM, ):
# EPERM == 1 == unknown host
break
if err.errno not in (errno.ENOENT, errno.EAGAIN):
# ENOENT == 2 == UDP Packet lost?
# EAGAIN == "try again"
raise
except socket.herror as err:
if err.errno in (0, 1, 3, 4, ):
# numeric values from linux netdb.h:
# 0 == Resolver Error 0 (no error), e.g. Host x.x.x.x.in-addr.arpa not found: 2(SERVFAIL)
# 1 == HOST_NOT_FOUND (Authoritative Answer Host not found)
# 3 == NO_RECOVERY (Non recoverable errors, FORMERR, REFUSED, NOTIMP)
# 4 == NO_DATA (Valid name, no data record of requested type)
break # give up
elif err.errno in (2, ):
# 2 == TRY_AGAIN (Non-Authoritative Host not found, or SERVERFAIL)
pass # retry
else:
# something with no specific handling yet
raise # crash
time.sleep(delay)
delay *= 2
return ''
Expand Down Expand Up @@ -381,10 +387,10 @@ def update_ns(fqdn, rdtype='A', ipaddr=None, action='upd', ttl=60):
raise DnsUpdateError(rcode_text)
return response
# TODO simplify exception handling when https://github.com/rthalley/dnspython/pull/85 is merged/released
except socket.error as e:
logger.error("socket.error [%s] - zone: %s" % (str(e), origin, ))
except OSError as e: # was: socket.error (deprecated)
logger.error("OSError [%s] - zone: %s" % (str(e), origin, ))
set_ns_availability(domain, False)
raise DnsUpdateError("SocketError %d" % e.errno)
raise DnsUpdateError("OSError %s - zone: %s" % (str(e), origin, ))
except EOFError as e:
logger.error("EOFError [%s] - zone: %s" % (str(e), origin, ))
set_ns_availability(domain, False)
Expand Down
2 changes: 1 addition & 1 deletion src/nsupdate/main/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ def form_valid(self, form):
success, level, msg = False, messages.ERROR, 'Host already exists in DNS.'
except dnstools.DNSException as e:
success, level, msg = False, messages.ERROR, 'DNSException [%s]' % str(e)
except socket.error as err:
except OSError as err: # was: socket.error (deprecated)
success, level, msg = False, messages.ERROR, 'Communication to name server failed [%s]' % str(err)
else:
self.object.created_by = self.request.user
Expand Down

0 comments on commit 2d8b44b

Please sign in to comment.