diff options
author | Avery Pennarun <apenwarr@gmail.com> | 2011-04-06 12:30:12 -0400 |
---|---|---|
committer | Avery Pennarun <apenwarr@gmail.com> | 2011-04-06 12:30:12 -0400 |
commit | 783d33cada4bbb7282877330abd7b16c7e2ab1fe (patch) | |
tree | 813a84407350ec692fa389e3d140a6438c8d1ca1 | |
parent | 94241b938bcf92a06d1b07184deca98349ab363f (diff) |
DNS: auto-retry if we get an error on send/recv to DNS server.
A few people have reported that they have one or more invalid DNS servers in
/etc/resolv.conf, which they don't notice because the normal resolver
library just skips the broken ones. sshuttle would abort because it got an
unexpected socket error, which isn't so good.
-rw-r--r-- | server.py | 42 |
1 files changed, 35 insertions, 7 deletions
@@ -110,23 +110,51 @@ class DnsProxy(Handler): def __init__(self, mux, chan, request): sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) Handler.__init__(self, [sock]) - self.sock = sock self.timeout = time.time()+30 self.mux = mux self.chan = chan + self.tries = 0 + self.peer = None + self.request = request + self.sock = sock self.sock.setsockopt(socket.SOL_IP, socket.IP_TTL, 42) - self.sock.connect((resolvconf_random_nameserver(), 53)) - self.sock.send(request) + self.try_send() + + def try_send(self): + if self.tries >= 3: + return + self.tries += 1 + self.peer = resolvconf_random_nameserver() + self.sock.connect((self.peer, 53)) + debug2('DNS: sending to %r\n' % self.peer) + try: + self.sock.send(self.request) + except socket.error, e: + if e.args[0] in [errno.ECONNREFUSED, errno.EHOSTUNREACH]: + # might have been spurious; try again. + # Note: these errors sometimes are reported by recv(), + # and sometimes by send(). We have to catch both. + debug2('DNS send to %r: %s\n' % (self.peer, e)) + self.try_send() + return + else: + log('DNS send to %r: %s\n' % (self.peer, e)) + return def callback(self): try: data = self.sock.recv(4096) except socket.error, e: - if e.args[0] == errno.ECONNREFUSED: - debug2('DNS response: ignoring ECONNREFUSED.\n') - return # might have been spurious; wait for a real answer + if e.args[0] in [errno.ECONNREFUSED, errno.EHOSTUNREACH]: + # might have been spurious; try again. + # Note: these errors sometimes are reported by recv(), + # and sometimes by send(). We have to catch both. + debug2('DNS recv from %r: %s\n' % (self.peer, e)) + self.try_send() + return else: - raise + log('DNS recv from %r: %s\n' % (self.peer, e)) + return debug2('DNS response: %d bytes\n' % len(data)) self.mux.send(self.chan, ssnet.CMD_DNS_RESPONSE, data) self.ok = False |