DNS bootstrap over Tor
If proxy type is SOCKS5, it will try to perform DNS bootstrap using the Tor RESOLVE extension.
This commit is contained in:
parent
1e89616c0f
commit
d75533c6b6
|
@ -5,6 +5,7 @@ import pickle
|
|||
import time
|
||||
|
||||
from debug import logger
|
||||
import socks
|
||||
|
||||
def knownNodes():
|
||||
try:
|
||||
|
@ -37,7 +38,6 @@ def dns():
|
|||
# defaultKnownNodes.py. Hopefully either they are up to date or the user
|
||||
# has run Bitmessage recently without SOCKS turned on and received good
|
||||
# bootstrap nodes using that method.
|
||||
with shared.printLock:
|
||||
if shared.config.get('bitmessagesettings', 'socksproxytype') == 'none':
|
||||
try:
|
||||
for item in socket.getaddrinfo('bootstrap8080.bitmessage.org', 80):
|
||||
|
@ -51,6 +51,38 @@ def dns():
|
|||
shared.knownNodes[1][shared.Peer(item[4][0], 8444)] = int(time.time())
|
||||
except:
|
||||
logger.error('bootstrap8444.bitmessage.org DNS bootstrapping failed.')
|
||||
elif shared.config.get('bitmessagesettings', 'socksproxytype') == 'SOCKS5':
|
||||
for port in [8080, 8444]:
|
||||
logger.debug("Resolving %i through SOCKS...", port)
|
||||
address_family = socket.AF_INET
|
||||
sock = socks.socksocket(address_family, socket.SOCK_STREAM)
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
sock.settimeout(20)
|
||||
proxytype = socks.PROXY_TYPE_SOCKS5
|
||||
sockshostname = shared.config.get(
|
||||
'bitmessagesettings', 'sockshostname')
|
||||
socksport = shared.config.getint(
|
||||
'bitmessagesettings', 'socksport')
|
||||
rdns = True # Do domain name lookups through the proxy; though this setting doesn't really matter since we won't be doing any domain name lookups anyway.
|
||||
if shared.config.getboolean('bitmessagesettings', 'socksauthentication'):
|
||||
socksusername = shared.config.get(
|
||||
'bitmessagesettings', 'socksusername')
|
||||
sockspassword = shared.config.get(
|
||||
'bitmessagesettings', 'sockspassword')
|
||||
sock.setproxy(
|
||||
proxytype, sockshostname, socksport, rdns, socksusername, sockspassword)
|
||||
else:
|
||||
logger.info('DNS bootstrap skipped because SOCKS is used.')
|
||||
sock.setproxy(
|
||||
proxytype, sockshostname, socksport, rdns)
|
||||
try:
|
||||
ip = sock.resolve("bootstrap" + str(port) + ".bitmessage.org")
|
||||
sock.shutdown(socket.SHUT_RDWR)
|
||||
sock.close()
|
||||
except:
|
||||
logger.error("SOCKS DNS resolving failed", exc_info=True)
|
||||
if ip is not None:
|
||||
logger.info ('Adding ' + ip + ' to knownNodes based on SOCKS DNS bootstrap method')
|
||||
shared.knownNodes[1][shared.Peer(ip, port)] = time.time()
|
||||
else:
|
||||
logger.info('DNS bootstrap skipped because the proxy type does not support DNS resolution.')
|
||||
|
||||
|
|
|
@ -155,7 +155,7 @@ class socksocket(socket.socket):
|
|||
"""
|
||||
self.__proxy = (proxytype, addr, port, rdns, username, password)
|
||||
|
||||
def __negotiatesocks5(self, destaddr, destport):
|
||||
def __negotiatesocks5(self):
|
||||
"""__negotiatesocks5(self,destaddr,destport)
|
||||
Negotiates a connection through a SOCKS5 server.
|
||||
"""
|
||||
|
@ -200,6 +200,8 @@ class socksocket(socket.socket):
|
|||
raise Socks5AuthError((2, _socks5autherrors[2]))
|
||||
else:
|
||||
raise GeneralProxyError((1, _generalerrors[1]))
|
||||
|
||||
def __connectsocks5(self, destaddr, destport):
|
||||
# Now we can request the actual connection
|
||||
req = struct.pack('BBB', 0x05, 0x01, 0x00)
|
||||
# If the given destination address is an IP address, we'll
|
||||
|
@ -247,6 +249,37 @@ class socksocket(socket.socket):
|
|||
else:
|
||||
self.__proxypeername = (destaddr, destport)
|
||||
|
||||
def __resolvesocks5(self, host):
|
||||
# Now we can request the actual connection
|
||||
req = struct.pack('BBB', 0x05, 0xF0, 0x00)
|
||||
req += chr(0x03).encode() + chr(len(host)).encode() + host
|
||||
req = req + struct.pack(">H", 8444)
|
||||
self.sendall(req)
|
||||
# Get the response
|
||||
ip = ""
|
||||
resp = self.__recvall(4)
|
||||
if resp[0:1] != chr(0x05).encode():
|
||||
self.close()
|
||||
raise GeneralProxyError((1, _generalerrors[1]))
|
||||
elif resp[1:2] != chr(0x00).encode():
|
||||
# Connection failed
|
||||
self.close()
|
||||
if ord(resp[1:2])<=8:
|
||||
raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])]))
|
||||
else:
|
||||
raise Socks5Error((9, _socks5errors[9]))
|
||||
# Get the bound address/port
|
||||
elif resp[3:4] == chr(0x01).encode():
|
||||
ip = socket.inet_ntoa(self.__recvall(4))
|
||||
elif resp[3:4] == chr(0x03).encode():
|
||||
resp = resp + self.recv(1)
|
||||
ip = self.__recvall(ord(resp[4:5]))
|
||||
else:
|
||||
self.close()
|
||||
raise GeneralProxyError((1,_generalerrors[1]))
|
||||
boundport = struct.unpack(">H", self.__recvall(2))[0]
|
||||
return ip
|
||||
|
||||
def getproxysockname(self):
|
||||
"""getsockname() -> address info
|
||||
Returns the bound IP address and port number at the proxy.
|
||||
|
@ -361,7 +394,8 @@ class socksocket(socket.socket):
|
|||
else:
|
||||
portnum = 1080
|
||||
_orgsocket.connect(self, (self.__proxy[1], portnum))
|
||||
self.__negotiatesocks5(destpair[0], destpair[1])
|
||||
self.__negotiatesocks5()
|
||||
self.__connectsocks5(destpair[0], destpair[1])
|
||||
elif self.__proxy[0] == PROXY_TYPE_SOCKS4:
|
||||
if self.__proxy[2] != None:
|
||||
portnum = self.__proxy[2]
|
||||
|
@ -380,3 +414,15 @@ class socksocket(socket.socket):
|
|||
_orgsocket.connect(self, (destpair[0], destpair[1]))
|
||||
else:
|
||||
raise GeneralProxyError((4, _generalerrors[4]))
|
||||
|
||||
def resolve(self, host):
|
||||
if self.__proxy[0] == PROXY_TYPE_SOCKS5:
|
||||
if self.__proxy[2] != None:
|
||||
portnum = self.__proxy[2]
|
||||
else:
|
||||
portnum = 1080
|
||||
_orgsocket.connect(self, (self.__proxy[1], portnum))
|
||||
self.__negotiatesocks5()
|
||||
return self.__resolvesocks5(host)
|
||||
else:
|
||||
return None
|
Loading…
Reference in New Issue
Block a user