added tunnel check

This commit is contained in:
Adolfo Gómez García 2021-01-18 06:45:50 +01:00
parent 7e4975be99
commit f364b283e6
4 changed files with 93 additions and 65 deletions

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2020 Virtual Cable S.L.U.
# Copyright (c) 2021 Virtual Cable S.L.U.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
@ -72,8 +72,7 @@ class ForwardServer(socketserver.ThreadingTCPServer):
check_certificate: bool = True,
) -> None:
if local_port == 0:
local_port = random.randrange(33000, 53000)
local_port = local_port or random.randrange(33000, 53000)
super().__init__(
server_address=(LISTEN_ADDRESS, local_port), RequestHandlerClass=Handler
@ -104,6 +103,36 @@ class ForwardServer(socketserver.ThreadingTCPServer):
self.timer = None
self.shutdown()
def connect(self) -> ssl.SSLSocket:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as rsocket:
logger.info('CONNECT to %s', self.remote)
rsocket.connect(self.remote)
context = ssl.create_default_context()
# If ignore remote certificate
if self.check_certificate is False:
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
logger.warning('Certificate checking is disabled!')
return context.wrap_socket(rsocket, server_hostname=self.remote[0])
def check(self) -> bool:
try:
with self.connect() as ssl_socket:
ssl_socket.sendall(HANDSHAKE_V1 + b'TEST')
resp = ssl_socket.recv(2)
if resp != b'OK':
raise Exception({'Invalid tunnelresponse: {resp}'})
return True
except Exception as e:
logger.error(
'Error connecting to tunnel server %s: %s', self.server_address, e
)
return False
@property
def stoppable(self) -> bool:
return self.timeout != 0 and int(time.time()) > self.timeout
@ -132,37 +161,18 @@ class Handler(socketserver.BaseRequestHandler):
# Open remote connection
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as rsocket:
logger.info('CONNECT to %s', self.server.remote)
logger.debug('Ticket %s', self.server.ticket)
logger.debug('Ticket %s', self.server.ticket)
with self.server.connect() as ssl_socket:
# Send handhshake + command + ticket
ssl_socket.sendall(HANDSHAKE_V1 + b'OPEN' + self.server.ticket.encode())
# Check response is OK
data = ssl_socket.recv(2)
if data != b'OK':
data += ssl_socket.recv(128)
raise Exception(f'Error received: {data.decode(errors="ignore")}') # Notify error
rsocket.connect(self.server.remote)
context = ssl.create_default_context()
# If ignore remote certificate
if self.server.check_certificate is False:
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
logger.warning('Certificate checking is disabled!')
with context.wrap_socket(
rsocket, server_hostname=self.server.remote[0]
) as ssl_socket:
# Send handhshake + command + ticket
ssl_socket.sendall(
HANDSHAKE_V1 + b'OPEN' + self.server.ticket.encode()
)
# Check response is OK
data = ssl_socket.recv(2)
if data != b'OK':
data += ssl_socket.recv(128)
raise Exception(
f'Error received: {data.decode()}'
) # Notify error
# All is fine, now we can tunnel data
self.process(remote=ssl_socket)
# All is fine, now we can tunnel data
self.process(remote=ssl_socket)
except Exception as e:
logger.error(f'Error connecting to {self.server.remote!s}: {e!s}')
self.server.status = TUNNEL_ERROR

View File

@ -43,4 +43,8 @@ else:
# Open tunnel
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk'])
# Check that tunnel works..
if fs.check() is False:
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
fnc(app, fs.server_address[1])

View File

@ -1 +1 @@
EGqTg6L0Bu5sqIA7BEUJgNzEwlQkPXfmdXLJ4iA+mRmXx6Z7QCXTYmxdqXmalUKUy4P2x3DvYMut5sM1BTWBYs6LxlE1CbuzBxEOw4VQHXDeW10Zir6C92IOevMZctrJS2zBNIB6RMddhD7HFwQ7LQ/yorUCClXUszjhcCxaTkqjM3KdbVuA4a+R9KF6gHHKCnjGrQXHuGdXjYm2+CRBWv5GBN57htO0VBEvCIrq7ZM/NzWDjBLlsrbkyUHxUoX3Tq0vXS03F3Gu3cxCP24yfYZoJeAHF4iOzU9XqomAYHvhNFEl7bvZz3ZyAIieT+zJJ+/WtGLjxL+ek8Va7V1ZYw9bWYnY0YyEkccupfoOXBy+phCJvcT6UgsL2dRO3yJma+GwejZAzv0JuDCvRmXN/xTbuSexyjIN7fLTmwT8q3DCA+m1CXXEQxLv9D1v2rhGPQOhwvomMKNRwZP3fi1zwL9d0FkgRnS36cz6+YLSf1dyXBDWK3Ez0vqJlRmLVz4GmVuidEnQ1pigzL3HLh3X32b9bd4nqCdSAVqP4dDcZsAQuf7JWYF0k7fA91ROT8nNEVg0zyN/YZU2Qxcr16fyVq1aBTTsDuEnKe0x0GruBRgEBU6Fr1i4eirgpcD+FddlLPvGUvgyH2lfotTcub+sL/BcgOaRvG7niiysJGfCxkc=
reSq28zy09GuLeWFzfhCRDX8AvYc8SQRBpIE7T7fjiHt1Cb4/KlA2sPaSuSDLI3SCI5vFSfXmm1QHesq/y0sDrs2xnZnz6BiVSXFjBBg4J6BM05QIs41u5deAe1lk/2RziColBt0Nnc75iSuLnHTt4SWYAFpjN7CKR3JcESD2gUZRpPJIfXXfgyfmlnOa1h6TGJBwANOlayV3qGzJv47mi0yw7VATFYcQtxtIqDCQeJI94IcC4PMvAeF/PBmBNfJAy0UArNhPYmnOrE38MkaMQQZkwVOWU1b1NuBjIPigYigcagjX8S75Vk83OniHnBRsW4MyhLJJuBy0+RG0WrBa0jT25Ggm76ORZuMWHTXK3x2ccxA060QMzplVFA4VwU+E9WcZWP0P2M6U9JuhWCogP5J1ufozHgiUUx1B6oC4qoThojNzVQgvgAhg/r/iEpOm13LP3+Yy2Cegiuf2KegPBJnAM8vB/I34YhGL8kDwgu7gWdeJUle1WkDVpndnl+eLRdqV301FBXaCaUZuh2NxA9gmFZjAYiOK0NlO9pLn7ATsqg+e8T+fli6aeIZahtfRCzGTIfYkL+ugxzZg3KnxjSnXPx6BxdeugKHsSGldwkx0iwWe2btlDBu2KO7Tws7FZMwd4nfHc4N4GHR1nWxam88X4R4VCEcUbkTIQJZsew=

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2020 Virtual Cable S.L.U.
# Copyright (c) 2021 Virtual Cable S.L.U.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
@ -103,6 +103,36 @@ class ForwardServer(socketserver.ThreadingTCPServer):
self.timer = None
self.shutdown()
def connect(self) -> ssl.SSLSocket:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as rsocket:
logger.info('CONNECT to %s', self.remote)
rsocket.connect(self.remote)
context = ssl.create_default_context()
# If ignore remote certificate
if self.check_certificate is False:
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
logger.warning('Certificate checking is disabled!')
return context.wrap_socket(rsocket, server_hostname=self.remote[0])
def check(self) -> bool:
try:
with self.connect() as ssl_socket:
ssl_socket.sendall(HANDSHAKE_V1 + b'TEST')
resp = ssl_socket.recv(2)
if resp != b'OK':
raise Exception({'Invalid tunnelresponse: {resp}'})
return True
except Exception as e:
logger.error(
'Error connecting to tunnel server %s: %s', self.server_address, e
)
return False
@property
def stoppable(self) -> bool:
return self.timeout != 0 and int(time.time()) > self.timeout
@ -131,37 +161,18 @@ class Handler(socketserver.BaseRequestHandler):
# Open remote connection
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as rsocket:
logger.info('CONNECT to %s', self.server.remote)
logger.debug('Ticket %s', self.server.ticket)
logger.debug('Ticket %s', self.server.ticket)
with self.server.connect() as ssl_socket:
# Send handhshake + command + ticket
ssl_socket.sendall(HANDSHAKE_V1 + b'OPEN' + self.server.ticket.encode())
# Check response is OK
data = ssl_socket.recv(2)
if data != b'OK':
data += ssl_socket.recv(128)
raise Exception(f'Error received: {data.decode(errors="ignore")}') # Notify error
rsocket.connect(self.server.remote)
context = ssl.create_default_context()
# If ignore remote certificate
if self.server.check_certificate is False:
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
logger.warning('Certificate checking is disabled!')
with context.wrap_socket(
rsocket, server_hostname=self.server.remote[0]
) as ssl_socket:
# Send handhshake + command + ticket
ssl_socket.sendall(
HANDSHAKE_V1 + b'OPEN' + self.server.ticket.encode()
)
# Check response is OK
data = ssl_socket.recv(2)
if data != b'OK':
data += ssl_socket.recv(128)
raise Exception(
f'Error received: {data.decode()}'
) # Notify error
# All is fine, now we can tunnel data
self.process(remote=ssl_socket)
# All is fine, now we can tunnel data
self.process(remote=ssl_socket)
except Exception as e:
logger.error(f'Error connecting to {self.server.remote!s}: {e!s}')
self.server.status = TUNNEL_ERROR
@ -249,3 +260,6 @@ if __name__ == "__main__":
timeout=60,
check_certificate=False,
)
print(fs.check())
fs.stop()