Skip to content

Commit 8771bee

Browse files
support looking up remote name resolving with SOCKS5
1 parent 512d0a0 commit 8771bee

File tree

2 files changed

+52
-19
lines changed

2 files changed

+52
-19
lines changed

kafka/conn.py

100644100755
Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -366,35 +366,46 @@ def connect_blocking(self, timeout=float('inf')):
366366

367367
def connect(self):
368368
"""Attempt to connect and return ConnectionState"""
369+
if self.config["socks5_proxy"] is not None and self._socks5_proxy is None:
370+
self._socks5_proxy = Socks5Wrapper(self.config["socks5_proxy"], self.afi)
371+
369372
if self.state is ConnectionStates.DISCONNECTED and not self.blacked_out():
370373
self.state = ConnectionStates.CONNECTING
371374
self.last_attempt = time.time()
372-
next_lookup = self._next_afi_sockaddr()
373-
if not next_lookup:
374-
self.close(Errors.KafkaConnectionError('DNS failure'))
375-
return self.state
376-
else:
375+
if self.config["socks5_proxy"] is None or not self._socks5_proxy.use_remote_lookup():
376+
next_lookup = self._next_afi_sockaddr()
377+
if not next_lookup:
378+
self.close(Errors.KafkaConnectionError('DNS failure'))
379+
return self.state
380+
377381
log.debug('%s: creating new socket', self)
378382
assert self._sock is None
379383
self._sock_afi, self._sock_addr = next_lookup
380384
try:
381385
if self.config["socks5_proxy"] is not None:
382-
self._socks5_proxy = Socks5Wrapper(self.config["socks5_proxy"], self.afi)
383386
self._sock = self._socks5_proxy.socket(self._sock_afi, socket.SOCK_STREAM)
384387
else:
385388
self._sock = socket.socket(self._sock_afi, socket.SOCK_STREAM)
386389
except (socket.error, OSError) as e:
387390
self.close(e)
388391
return self.state
392+
else:
393+
self._sock = self._socks5_proxy.socket(None, socket.SOCK_STREAM)
394+
self._sock_afi = None
395+
self._sock_addr = [self.host.encode('ascii'), self.port]
389396

390397
for option in self.config['socket_options']:
391398
log.debug('%s: setting socket option %s', self, option)
392399
self._sock.setsockopt(*option)
393400

394401
self._sock.setblocking(False)
395402
self.config['state_change_callback'](self.node_id, self._sock, self)
403+
if self._sock_afi != None:
404+
family_str = AFI_NAMES[self._sock_afi]
405+
else:
406+
family_str = "n.a."
396407
log.info('%s: connecting to %s:%d [%s %s]', self, self.host,
397-
self.port, self._sock_addr, AFI_NAMES[self._sock_afi])
408+
self.port, self._sock_addr, family_str)
398409

399410
if self.state is ConnectionStates.CONNECTING:
400411
# in non-blocking mode, use repeated calls to socket.connect_ex
@@ -862,7 +873,7 @@ def connection_delay(self):
862873
large number to handle slow/stalled connections.
863874
"""
864875
if self.disconnected() or self.connecting():
865-
if len(self._gai) > 0:
876+
if len(self._gai) > 0 or self._socks5_proxy.use_remote_lookup():
866877
return 0
867878
else:
868879
time_waited = time.time() - self.last_attempt
@@ -1291,9 +1302,13 @@ def check_version(self, timeout=2, **kwargs):
12911302
return self._api_version
12921303

12931304
def __str__(self):
1305+
if self._sock_afi != None:
1306+
family_str = AFI_NAMES[self._sock_afi]
1307+
else:
1308+
family_str = "n.a."
12941309
return "<BrokerConnection client_id=%s, node_id=%s host=%s:%d %s [%s %s]>" % (
12951310
self.config['client_id'], self.node_id, self.host, self.port, self.state,
1296-
AFI_NAMES[self._sock_afi], self._sock_addr)
1311+
family_str, self._sock_addr)
12971312

12981313

12991314
class BrokerConnectionMetrics(object):

kafka/socks5_wrapper.py

100644100755
Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ def dns_lookup(cls, host, port, afi=socket.AF_UNSPEC):
6464
log.warning("DNS lookup failed for proxy %s:%d, %r", host, port, ex)
6565
return []
6666

67+
def use_remote_lookup(self):
68+
return self._proxy_url.scheme == 'socks5h'
69+
6770
def socket(self, family, sock_type):
6871
"""Open and record a socket.
6972
@@ -187,7 +190,10 @@ def connect_ex(self, addr):
187190
return errno.ECONNREFUSED
188191

189192
if self._state == ProxyConnectionStates.REQUEST_SUBMIT:
190-
if self._target_afi == socket.AF_INET:
193+
if self.use_remote_lookup():
194+
addr_type = 3
195+
addr_len = len(addr[0])
196+
elif self._target_afi == socket.AF_INET:
191197
addr_type = 1
192198
addr_len = 4
193199
elif self._target_afi == socket.AF_INET6:
@@ -199,15 +205,27 @@ def connect_ex(self, addr):
199205
self._sock.close()
200206
return errno.ECONNREFUSED
201207

202-
self._buffer_out = struct.pack(
203-
"!bbbb{}sh".format(addr_len),
204-
5, # version
205-
1, # command: connect
206-
0, # reserved
207-
addr_type, # 1 for ipv4, 4 for ipv6 address
208-
socket.inet_pton(self._target_afi, addr[0]), # either 4 or 16 bytes of actual address
209-
addr[1], # port
210-
)
208+
if self.use_remote_lookup():
209+
self._buffer_out = struct.pack(
210+
"!bbbbb{}sh".format(addr_len),
211+
5, # version
212+
1, # command: connect
213+
0, # reserved
214+
addr_type, # 1 for ipv4, 4 for ipv6 address, 3 for domain name
215+
addr_len,
216+
addr[0], # host
217+
addr[1], # port
218+
)
219+
else:
220+
self._buffer_out = struct.pack(
221+
"!bbbb{}sh".format(addr_len),
222+
5, # version
223+
1, # command: connect
224+
0, # reserved
225+
addr_type, # 1 for ipv4, 4 for ipv6 address, 3 for domain name
226+
socket.inet_pton(self._target_afi, addr[0]), # either 4 or 16 bytes of actual address
227+
addr[1], # port
228+
)
211229
self._state = ProxyConnectionStates.REQUESTING
212230

213231
if self._state == ProxyConnectionStates.REQUESTING:

0 commit comments

Comments
 (0)