Skip to content

Commit 783d33c

Browse files
committed
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.
1 parent 94241b9 commit 783d33c

File tree

1 file changed

+35
-7
lines changed

1 file changed

+35
-7
lines changed

server.py

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,23 +110,51 @@ class DnsProxy(Handler):
110110
def __init__(self, mux, chan, request):
111111
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
112112
Handler.__init__(self, [sock])
113-
self.sock = sock
114113
self.timeout = time.time()+30
115114
self.mux = mux
116115
self.chan = chan
116+
self.tries = 0
117+
self.peer = None
118+
self.request = request
119+
self.sock = sock
117120
self.sock.setsockopt(socket.SOL_IP, socket.IP_TTL, 42)
118-
self.sock.connect((resolvconf_random_nameserver(), 53))
119-
self.sock.send(request)
121+
self.try_send()
122+
123+
def try_send(self):
124+
if self.tries >= 3:
125+
return
126+
self.tries += 1
127+
self.peer = resolvconf_random_nameserver()
128+
self.sock.connect((self.peer, 53))
129+
debug2('DNS: sending to %r\n' % self.peer)
130+
try:
131+
self.sock.send(self.request)
132+
except socket.error, e:
133+
if e.args[0] in [errno.ECONNREFUSED, errno.EHOSTUNREACH]:
134+
# might have been spurious; try again.
135+
# Note: these errors sometimes are reported by recv(),
136+
# and sometimes by send(). We have to catch both.
137+
debug2('DNS send to %r: %s\n' % (self.peer, e))
138+
self.try_send()
139+
return
140+
else:
141+
log('DNS send to %r: %s\n' % (self.peer, e))
142+
return
120143

121144
def callback(self):
122145
try:
123146
data = self.sock.recv(4096)
124147
except socket.error, e:
125-
if e.args[0] == errno.ECONNREFUSED:
126-
debug2('DNS response: ignoring ECONNREFUSED.\n')
127-
return # might have been spurious; wait for a real answer
148+
if e.args[0] in [errno.ECONNREFUSED, errno.EHOSTUNREACH]:
149+
# might have been spurious; try again.
150+
# Note: these errors sometimes are reported by recv(),
151+
# and sometimes by send(). We have to catch both.
152+
debug2('DNS recv from %r: %s\n' % (self.peer, e))
153+
self.try_send()
154+
return
128155
else:
129-
raise
156+
log('DNS recv from %r: %s\n' % (self.peer, e))
157+
return
130158
debug2('DNS response: %d bytes\n' % len(data))
131159
self.mux.send(self.chan, ssnet.CMD_DNS_RESPONSE, data)
132160
self.ok = False

0 commit comments

Comments
 (0)