Initial commit.

This commit is contained in:
retoor 2024-12-08 10:32:43 +01:00
parent 5d3d6a0247
commit 0dffc6bdd8
6 changed files with 171 additions and 0 deletions

31
Makefile Normal file
View File

@ -0,0 +1,31 @@
BIN = ./.venv/bin/
PYTHON = ./.venv/bin/python
PIP = ./.venv/bin/pip
APP_NAME=shadowssh
all: install build
ensure_repo:
-@git init
ensure_env: ensure_repo
-@python3 -m venv .venv
install:
$(PIP) install -e .
format:
$(PIP) install shed
. $(BIN)/activate && shed
build: install format
$(PIP) install build
$(PYTHON) -m build
serve:
$(BIN)$(APP_NAME).serve --host=0.0.0.0 --port=443
run: serve

3
pyproject.toml Normal file
View File

@ -0,0 +1,3 @@
[build-system]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"

25
setup.cfg Normal file
View File

@ -0,0 +1,25 @@
[metadata]
name = shadowssh
version = 1.0.0
description = Run ssh on other service port!
author = retoor
author_email = retoor@molodetz.nl
license = MIT
long_description = file: README.md
long_description_content_type = text/markdown
[options]
packages = find:
package_dir =
= src
python_requires = >=3.7
install_requires =
app @ git+https://retoor.molodetz.nl/retoor/app.git
mololog @git+https://retoor.molodetz.nl/retoor/mololog.git
[options.packages.find]
where = src
[options.entry_points]
console_scripts =
shadowssh.serve = shadowssh.__main__:serve

View File

@ -0,0 +1,9 @@
import logging
from mololog.client import patch
logging.basicConfig(
level = logging.INFO
)
log = logging.getLogger()
patch("https://mololog.molodetz.nl/")

25
src/shadowssh/__main__.py Normal file
View File

@ -0,0 +1,25 @@
from shadowssh.app import Application
import asyncio
import argparse
def parse_args():
parser = argparse.ArgumentParser(description="Shadowssh")
parser.add_argument("--host",type=str,required=False,default="0.0.0.0")
parser.add_argument("--port",type=int,required=False,default=443)
parser.add_argument("--host-service",type=str,required=False,default="127.0.0.1")
parser.add_argument("--port-service",type=int,required=False,default=4433)
parser.add_argument("--host-ssh", type=str,required=False,default="127.0.0.1")
parser.add_argument("--port-ssh", type=int,required=False,default=22)
return parser.parse_args()
def serve():
args = parse_args()
app = Application()
asyncio.run(app.serve(args.host,args.port,args.host_service,args.port_service,args.host_ssh,args.port_ssh))

78
src/shadowssh/app.py Normal file
View File

@ -0,0 +1,78 @@
import asyncio
from app.app import Application as BaseApplication
from shadowssh import log
class Application(BaseApplication):
def __init__(self, host_forward_service=None, port_forward_service=None, host_forward_ssh=None, port_forward_ssh=None, *args,**kwargs):
self.host_forward_service = host_forward_service
self.port_forward_service = port_forward_service
self.host_forward_ssh = host_forward_ssh
self.port_forward_ssh = port_forward_ssh
super().__init__(*args,**kwargs)
async def connect(self, host, port):
log.info("Connected to {}:{}.".format(host,port))
reader, writer = await asyncio.open_connection(host, port)
return reader,writer
async def stream(self, reader, writer,port):
while True:
chunk = await reader.read(4096)
if not chunk:
writer.close()
log.info("Forward connection closed.")
return
writer.write(chunk)
await writer.drain()
async def forward(self, reader, writer):
data = await reader.read(10)
if not data:
return
port = None
host = None
if b'SSH-2.0' in data:
port = self.port_forward_ssh
host = self.host_forward_ssh
else:
port = self.port_forward_service
host = self.host_forward_service
log.info("Streaming to port: {}.".format(port))
upstream_reader, upstream_writer = await self.connect(host, port)
upstream_writer.write(data)
tasks = []
tasks.append(asyncio.create_task(self.stream(reader, upstream_writer,port)))
tasks.append(asyncio.create_task(self.stream(upstream_reader, writer,port)))
await asyncio.gather(*tasks)
async def route(self, host, port):
async def handle_client(reader, writer):
await self.forward(reader, writer)
server = await asyncio.start_server(handle_client, host, port)
addr = server.sockets[0].getsockname()
log.info(f'Serving on {addr}')
async with server:
await server.serve_forever()
async def serve(self, host,port,host_forward_service, port_forward_service, host_forward_ssh, port_forward_ssh):
self.host_forward_service = host_forward_service
self.port_forward_service = port_forward_service
self.host_forward_ssh = host_forward_ssh
self.port_forward_ssh = port_forward_ssh
tasks = [
self.route(host,port)
]
await asyncio.gather(*tasks)