mirror of
https://github.com/sshuttle/sshuttle.git
synced 2025-04-13 22:09:02 +02:00
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.
This commit is contained in:
parent
94241b938b
commit
783d33cada
42
server.py
42
server.py
@ -110,23 +110,51 @@ class DnsProxy(Handler):
|
|||||||
def __init__(self, mux, chan, request):
|
def __init__(self, mux, chan, request):
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
Handler.__init__(self, [sock])
|
Handler.__init__(self, [sock])
|
||||||
self.sock = sock
|
|
||||||
self.timeout = time.time()+30
|
self.timeout = time.time()+30
|
||||||
self.mux = mux
|
self.mux = mux
|
||||||
self.chan = chan
|
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.setsockopt(socket.SOL_IP, socket.IP_TTL, 42)
|
||||||
self.sock.connect((resolvconf_random_nameserver(), 53))
|
self.try_send()
|
||||||
self.sock.send(request)
|
|
||||||
|
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):
|
def callback(self):
|
||||||
try:
|
try:
|
||||||
data = self.sock.recv(4096)
|
data = self.sock.recv(4096)
|
||||||
except socket.error, e:
|
except socket.error, e:
|
||||||
if e.args[0] == errno.ECONNREFUSED:
|
if e.args[0] in [errno.ECONNREFUSED, errno.EHOSTUNREACH]:
|
||||||
debug2('DNS response: ignoring ECONNREFUSED.\n')
|
# might have been spurious; try again.
|
||||||
return # might have been spurious; wait for a real answer
|
# 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:
|
else:
|
||||||
raise
|
log('DNS recv from %r: %s\n' % (self.peer, e))
|
||||||
|
return
|
||||||
debug2('DNS response: %d bytes\n' % len(data))
|
debug2('DNS response: %d bytes\n' % len(data))
|
||||||
self.mux.send(self.chan, ssnet.CMD_DNS_RESPONSE, data)
|
self.mux.send(self.chan, ssnet.CMD_DNS_RESPONSE, data)
|
||||||
self.ok = False
|
self.ok = False
|
||||||
|
Loading…
Reference in New Issue
Block a user