rename SFTelnetProxyMuxer.py to sftelnetproxymuxer.py. Set all inital options to False. Add check exception if remote_port or listen_port aren't defined.

pull/2345/head
John Fleming 4 months ago
parent 37bd4067b0
commit e39b317185

@ -3,20 +3,24 @@ import asyncio
import telnetlib3 import telnetlib3
import pdb import pdb
import logging import logging
log = logging.getLogger(__name__)
# Configure logging # Configure logging
logging.basicConfig( #log.basicConfig(
level=logging.DEBUG, # Set the logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL) # level=log.DEBUG, # Set the logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
format='%(asctime)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)', # format='%(asctime)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)',
datefmt='%Y-%m-%d %H:%M:%S' # datefmt='%Y-%m-%d %H:%M:%S'
) #)
class SFTelnetProxyMuxer: class SFTelnetProxyMuxer:
def __init__(self, remote_ip, remote_port, listen_ip, listen_port): def __init__(self, remote_ip=None, remote_port=None, listen_ip=None, listen_port=None, reader=None, writer=None, binary=True, echo=False, naws=False, window_size_changed_callback=None, connection_factory=None):
if remote_ip == None:
remote_ip = '127.0.0.1'
self.remote_ip = remote_ip self.remote_ip = remote_ip
self.remote_port = remote_port self.remote_port = remote_port
self.remote_info = f"('{self.remote_ip}', {self.remote_port})" self.remote_info = f"('{self.remote_ip}', {self.remote_port})"
if listen_ip == None:
listen_ip = '0.0.0.0'
self.listen_ip = listen_ip self.listen_ip = listen_ip
self.listen_port = listen_port self.listen_port = listen_port
self.clients = set() self.clients = set()
@ -30,16 +34,20 @@ class SFTelnetProxyMuxer:
self.NOP = b"\xf1" self.NOP = b"\xf1"
# Telnet Are You There # Telnet Are You There
self.AYT = b"\xf6" self.AYT = b"\xf6"
log.debug("SFTelnetProxyMuxer init complete")
if not remote_port:
raise ValueError("remote_port is a required value")
if not listen_port:
raise ValueError("listen_port is a required value")
logging.debug("TCPProxy init complete")
async def handle_client(self, reader, writer): async def handle_client(self, reader, writer):
client_info = writer.get_extra_info('peername') client_info = writer.get_extra_info('peername')
sock = writer.get_extra_info('socket') sock = writer.get_extra_info('socket')
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
logging.debug(f"New client connected: {client_info}") log.debug(f"New client connected: {client_info}")
self.clients.add(writer) self.clients.add(writer)
#logging.debug(f"Write idle: {writer.protocol.idle}") #log.debug(f"Write idle: {writer.protocol.idle}")
try: try:
await asyncio.sleep(1) await asyncio.sleep(1)
@ -48,76 +56,76 @@ class SFTelnetProxyMuxer:
# Set a timeout for the read operation, without should the socket closes after timeout. # Set a timeout for the read operation, without should the socket closes after timeout.
data = await asyncio.shield(asyncio.wait_for(reader.read((4*1024*1024)), timeout=2.0)) data = await asyncio.shield(asyncio.wait_for(reader.read((4*1024*1024)), timeout=2.0))
if not data: if not data:
logging.debug(f"No data. Not sure if this is possible.") log.debug(f"No data. Not sure if this is possible.")
break break
if reader.at_eof(): if reader.at_eof():
logging.info(f"Client {client_info} closed tcp session with eof.") log.info(f"Client {client_info} closed tcp session with eof.")
writer.close() writer.close()
self.clients.discard(writer) self.clients.discard(writer)
break break
async with self.lock: async with self.lock:
if self.remote_writer is not None: if self.remote_writer is not None:
logging.debug(f"Sending data from from client {client_info} to server {self.remote_info}") log.debug(f"Sending data from from client {client_info} to server {self.remote_info}")
self.remote_writer.write(data) self.remote_writer.write(data)
await self.remote_writer.drain() await self.remote_writer.drain()
continue continue
except asyncio.TimeoutError: except asyncio.TimeoutError:
logging.warning(f"No data read from {client_info}, send heartbeat to test client socket.") log.warning(f"No data read from {client_info}, send heartbeat to test client socket.")
try: try:
logging.warning(f"Heatbeat: Are you there {client_info}?") log.warning(f"Heatbeat: Are you there {client_info}?")
#pdb.set_trace() #pdb.set_trace()
writer.send_iac(self.IAC + self.NOP) writer.send_iac(self.IAC + self.NOP)
await writer.drain() await writer.drain()
continue continue
except asyncio.TimeoutError: except asyncio.TimeoutError:
logging.warning(f"Heatbeat: No reply from {client_info}, closing socket.") log.warning(f"Heatbeat: No reply from {client_info}, closing socket.")
writer.close() writer.close()
self.clients.discard(writer) self.clients.discard(writer)
break break
except Exception as e: except Exception as e:
logging.warning(f"Heateat: Unknown error from {client_info}, closing socket. Exeption {e}") log.warning(f"Heateat: Unknown error from {client_info}, closing socket. Exeption {e}")
writer.close() writer.close()
self.clients.discard(writer) self.clients.discard(writer)
break break
finally: finally:
logging.warning(f"Heatbeat: {client_info} Yes I am.") log.warning(f"Heatbeat: {client_info} Yes I am.")
except Exception as e: except Exception as e:
logging.exception(f"Error in handling data from client {client_info}:") log.exception(f"Error in handling data from client {client_info}:")
writer.close() writer.close()
self.clients.discard(writer) self.clients.discard(writer)
break break
except Exception as e: except Exception as e:
logging.exception(f"Error in managing client {client_info}: {e}") log.exception(f"Error in managing client {client_info}: {e}")
finally: finally:
# Safely remove the writer from clients set and close the connection # Safely remove the writer from clients set and close the connection
writer.close() writer.close()
self.clients.discard(writer) self.clients.discard(writer)
logging.debug(f"Client {client_info} disconnected. Remaining clients: {len(list(self.clients))}") log.debug(f"Client {client_info} disconnected. Remaining clients: {len(list(self.clients))}")
logging.debug(f"Connection with client {client_info} closed.") log.debug(f"Connection with client {client_info} closed.")
async def broadcast_to_clients(self, data): async def broadcast_to_clients(self, data):
if not self.clients: if not self.clients:
logging.debug(f"Warning: No clients connected, ignoring data.") log.debug(f"Warning: No clients connected, ignoring data.")
return return
for writer in set(self.clients): for writer in set(self.clients):
client_info = writer.get_extra_info('peername') client_info = writer.get_extra_info('peername')
try: try:
#logging.debug(f"Clients connected: {writer}, sending data: {data}") #log.debug(f"Clients connected: {writer}, sending data: {data}")
writer.write(data) writer.write(data)
await asyncio.wait_for(writer.drain(), timeout=2.0) await asyncio.wait_for(writer.drain(), timeout=2.0)
except Exception as e: except Exception as e:
logging.debug(f"Lost connection to client {client_info}") log.debug(f"Lost connection to client {client_info}")
writer.close() writer.close()
self.clients.discard(writer) self.clients.discard(writer)
async def handle_remote_server(self): async def handle_remote_server(self):
logging.debug("Start handler for remote server") log.debug("Start handler for remote server")
while True: while True:
await asyncio.sleep(1) await asyncio.sleep(1)
try: try:
@ -132,12 +140,12 @@ class SFTelnetProxyMuxer:
#data = await self.remote_reader.read((4*1024*1024)) #data = await self.remote_reader.read((4*1024*1024))
data = await asyncio.shield(asyncio.wait_for(self.remote_reader.read((4*1024*1024)), timeout=2.0)) data = await asyncio.shield(asyncio.wait_for(self.remote_reader.read((4*1024*1024)), timeout=2.0))
if self.remote_reader.at_eof(): if self.remote_reader.at_eof():
logging.info(f"Remote server {self.remote_info} closed tcp session with eof.") log.info(f"Remote server {self.remote_info} closed tcp session with eof.")
break break
except asyncio.TimeoutError: except asyncio.TimeoutError:
logging.warning(f"No data from server {self.remote_info}, send heartbeat to test socket.") log.warning(f"No data from server {self.remote_info}, send heartbeat to test socket.")
try: try:
logging.warning(f"Heatbeat: Are you there {self.remote_info}?") log.warning(f"Heatbeat: Are you there {self.remote_info}?")
# NOP and AYT cause QEMU to spam everyone's console with junk. # NOP and AYT cause QEMU to spam everyone's console with junk.
# This causes everyone to close the session and eof tcp which makes me sad. # This causes everyone to close the session and eof tcp which makes me sad.
# Will need to research more... or did i call this wrong and just fix it? # Will need to research more... or did i call this wrong and just fix it?
@ -145,60 +153,60 @@ class SFTelnetProxyMuxer:
await self.remote_writer.drain() await self.remote_writer.drain()
continue continue
except Exception as e: except Exception as e:
logging.warning(f"Heateat: Unknown error from {self.remote_info}, closing socket. Exeption {e}") log.warning(f"Heateat: Unknown error from {self.remote_info}, closing socket. Exeption {e}")
self.remote_writer.close() self.remote_writer.close()
break break
finally: finally:
logging.warning(f"Heatbeat: {self.remote_info} Yes I am.") log.warning(f"Heatbeat: {self.remote_info} Yes I am.")
except Exception as e: except Exception as e:
logging.debug("Failed to read socket data exception: {e}") log.debug("Failed to read socket data exception: {e}")
break break
#if not self.clients: #if not self.clients:
# logging.debug("No clients connected, but console data found. Skipping.") # log.debug("No clients connected, but console data found. Skipping.")
# continue # continue
#logging.debug("Sending data to clients data: {data}") #log.debug("Sending data to clients data: {data}")
await self.broadcast_to_clients(data) await self.broadcast_to_clients(data)
except ConnectionRefusedError as e: except ConnectionRefusedError as e:
error_msg = f"Warning: Connection to remote server {self.remote_info} refused." error_msg = f"Warning: Connection to remote server {self.remote_info} refused."
logging.debug(error_msg) log.debug(error_msg)
await self.broadcast_to_clients(f"\r{error_msg}\n\r") await self.broadcast_to_clients(f"\r{error_msg}\n\r")
except TimeoutError as e: except TimeoutError as e:
error_msg = f"Warning: Connection to remote server {self.remote_info} timedout." error_msg = f"Warning: Connection to remote server {self.remote_info} timedout."
logging.debug(error_msg) log.debug(error_msg)
await self.broadcast_to_clients(f"\r{error_msg}\n\r") await self.broadcast_to_clients(f"\r{error_msg}\n\r")
except Exception as e: except Exception as e:
error_msg = f"Warning: Connection to remote server {self.remote_info} unknown error: {e}." error_msg = f"Warning: Connection to remote server {self.remote_info} unknown error: {e}."
logging.debug(error_msg) log.debug(error_msg)
await self.broadcast_to_clients(f"\r{error_msg}\n\r") await self.broadcast_to_clients(f"\r{error_msg}\n\r")
async def start_proxy(self): async def start_proxy(self):
logging.debug("Starting telnet proxy.") log.debug("Starting telnet proxy.")
asyncio.create_task(self.handle_remote_server()) asyncio.create_task(self.handle_remote_server())
self.server = await telnetlib3.create_server( self.server = await telnetlib3.create_server(
host=self.listen_ip, port=self.listen_port, host=self.listen_ip, port=self.listen_port,
shell=self.handle_client shell=self.handle_client
) )
async with self.server: async with self.server:
logging.debug("Startup of telnet proxy complete.") log.debug("Startup of telnet proxy complete.")
await self.server.wait_closed() await self.server.wait_closed()
async def shutdown(self): async def shutdown(self):
# [shutdown method implementation remains the same] # [shutdown method implementation remains the same]
logging.debug("Debug message") log.debug("Debug message")
pass pass
if __name__ == "__main__": if __name__ == "__main__":
## Example usage ## Example usage
logging.debug("Start proxy") log.debug("Start proxy")
proxy = SFTelnetProxyMuxer(remote_ip='127.0.0.1', remote_port=7000, listen_ip='0.0.0.0', listen_port=8888) proxy = SFTelnetProxyMuxer(remote_ip='127.0.0.1', remote_port=7000, listen_ip='0.0.0.0', listen_port=8888)
try: try:
asyncio.wait_for(asyncio.run(proxy.start_proxy()), timeout=30) asyncio.wait_for(asyncio.run(proxy.start_proxy()), timeout=30)
except OSError as e: except OSError as e:
logging.debug(f"Can't start proxy: {e}") log.debug(f"Can't start proxy: {e}")
# To shut down the proxy # To shut down the proxy
# asyncio.run(proxy.shutdown()) # asyncio.run(proxy.shutdown())
Loading…
Cancel
Save