From 837caa17e0824253e707c8bf2e2f0fca7cf3f28f Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Mon, 20 Apr 2020 03:36:41 -0500 Subject: [PATCH] we now have two way communication --- .gitignore | 9 +++++ src/yam.py | 83 ++++++++++++++++++++++++++++++++++++---- src/youandme/__init__.py | 14 ++----- src/youandme/client.py | 40 +++++++++++++++++++ src/youandme/commands.py | 1 + src/youandme/server.py | 59 +++++++++++++--------------- src/youandme/tor.py | 2 +- tests/test.py | 7 ---- tests/test_client.py | 42 ++++++++++++++++++++ tests/test_server.py | 79 ++++++++++++++++++++++++++++++++++++++ 10 files changed, 277 insertions(+), 59 deletions(-) create mode 100644 .gitignore create mode 100644 src/youandme/client.py create mode 100644 src/youandme/commands.py delete mode 100644 tests/test.py create mode 100644 tests/test_client.py create mode 100644 tests/test_server.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2bcdca2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +venv/* +testdata/* +.vscode/* +.mypy_cache/* +youandme.egg-info/* +__pycache__/* +src/__pycache__/* +src/youandme.egg-info/* +src/youandme/__pycache__/* diff --git a/src/yam.py b/src/yam.py index 57ee9b9..e1a5be6 100644 --- a/src/yam.py +++ b/src/yam.py @@ -1,4 +1,10 @@ import sys +import socket +from time import time, sleep +from threading import Thread + +from getch import getch +from stem.control import Controller try: from youandme.tor import launch_tor @@ -6,16 +12,77 @@ except ModuleNotFoundError: pass from youandme.server import server +from youandme.client import client -def interactive_connector(): +class _Address: + address = "" + + +def connector(host, send_data, recv_data, address="", control_port=1337, socks_port=1338): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + result = sock.connect_ex(('127.0.0.1', socks_port)) + if result != 0: + launch_tor(control_port=control_port, socks_port=socks_port) + print(host) + if host: + with Controller.from_port(port=control_port) as controller: + controller.authenticate() + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + ip = '127.0.0.1' + s.bind((ip, 0)) + s.listen(1) + port = s.getsockname()[1] + serv = controller.create_ephemeral_hidden_service( + {1337: '127.0.0.1:' + str(port)}, + key_content='ED25519-V3', + await_publication=True, + ) + _Address.address = serv.service_id + conn, addr = s.accept() + server(1, controller, conn, send_data, recv_data) + else: + print('adderr', address) + if not address.endswith('.onion'): + address += '.onion' + client(1, address, socks_port, send_data, recv_data) + + +def chat(mode, send_data, recv_data): + if mode == 'host': + while _Address.address == "": + sleep(0.01) + print(_Address.address) + def display_new(): + while True: + try: + char = chr(recv_data.pop(0)) + print('') + print(char, end='') + except IndexError: + pass + sleep(0.1) + Thread(target=display_new, daemon=True).start() + def make_message(): + while True: + new = input().encode('utf-8') + for b in new: + send_data.append(b) + Thread(target=make_message, daemon=True).start() + while True: + sleep(1) - print("Starting Tor...") - launch_tor() - print("Tor started.") - server() if __name__ == "__main__": - if len(sys.argv) == 2: - if sys.argv[1] == 'interactive': - interactive_connector() + if len(sys.argv) >= 2: + if sys.argv[1] == 'chat': + send_data = bytearray() + recv_data = bytearray() + if sys.argv[2] == 'host': + Thread(target=connector, args=[True, send_data, recv_data], kwargs={'socks_port': int(input("socks")), 'control_port': int(input('control port'))}, daemon=True).start() + elif sys.argv[2].startswith('conn'): + Thread(target=connector, args=[False, send_data, recv_data], kwargs={'address': sys.argv[3], 'socks_port': int(input("socks")), 'control_port': int(input('control port'))}, daemon=True).start() + else: + print('Must specify host or conn') + sys.exit(1) + chat(sys.argv[2], send_data, recv_data) diff --git a/src/youandme/__init__.py b/src/youandme/__init__.py index 63d067a..531e40d 100644 --- a/src/youandme/__init__.py +++ b/src/youandme/__init__.py @@ -1,17 +1,11 @@ import sys +import stem + +OWN_TOR = False try: from .starttor import launch_tor + OWN_TOR = True except ModuleNotFoundError: pass -from .server import server - -def interactive_connector(): - server() - - -if __name__ == "__main__": - if len(sys.argv) == 2: - if sys.argv[1] == 'interactive': - interactive_connector() diff --git a/src/youandme/client.py b/src/youandme/client.py new file mode 100644 index 0000000..6b6a465 --- /dev/null +++ b/src/youandme/client.py @@ -0,0 +1,40 @@ +from threading import Thread +from time import sleep + +import socks + +from .commands import garbage_character + + +def client(delay: int, hs_id, socks_port, send_data: bytearray, recv_data: bytearray): + s = socks.socksocket() # Same API as socket.socket in the standard lib + + s.set_proxy(socks.SOCKS5, "127.0.0.1", socks_port, rdns=True) + + def send_loop(): + while True: + to_send = None + if send_data: + char = send_data.pop(0) + to_send = char + else: + to_send = garbage_character + try: + s.send(chr(to_send).encode('utf-8')) + except TypeError: + s.send(to_send) + except BrokenPipeError: + pass + sleep(delay) + + # Can be treated identical to a regular socket object + s.connect((hs_id, 1337)) + Thread(target=send_loop, daemon=True).start() + while True: + data = s.recv(1) + if data != garbage_character: + try: + recv_data.append(data) + except TypeError: + if data: + recv_data.append(ord(data)) diff --git a/src/youandme/commands.py b/src/youandme/commands.py new file mode 100644 index 0000000..f4e0dec --- /dev/null +++ b/src/youandme/commands.py @@ -0,0 +1 @@ +garbage_character = b'\x00' \ No newline at end of file diff --git a/src/youandme/server.py b/src/youandme/server.py index f0dfac4..86e6fea 100644 --- a/src/youandme/server.py +++ b/src/youandme/server.py @@ -1,41 +1,34 @@ import socket import time +from.commands import garbage_character -from stem.control import Controller from threading import Thread -def server(): - send_data = bytearray() - def send_loop(conn): +def server(delay: int, controller, conn, send_data: bytearray, recv_data: bytearray): + def send_loop(): while True: - time.sleep(0.1) - if not send_data: - conn.sendall(bytes([55])) - else: - conn.sendall(send_data.pop(0)) - with Controller.from_port(port=1338) as controller: - controller.authenticate() - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: - ip = '127.0.0.1' - s.bind((ip, 0)) - s.listen(1) - port = s.getsockname()[1] - serv = controller.create_ephemeral_hidden_service({ - 1337: f'{ip}:{port}'}, - key_content = 'ED25519-V3', - await_publication = True, - ) - print('on', serv.service_id, 'to', ip, port) - conn, addr = s.accept() - with conn: - Thread(target=send_loop, args=[conn], daemon=True).start() - print('Connected by', addr) - while True: - data = conn.recv(1) - if not data: break - data = data.strip() - if data != bytes([55]): - print(data) - #conn.sendall(data) + time.sleep(delay) + try: + if not send_data: + conn.sendall(garbage_character) + else: + char = send_data.pop(0) + try: + conn.sendall(ord(char)) + except TypeError: + try: + conn.sendall(char) + except TypeError: + conn.sendall(chr(char).encode('utf-8')) + except OSError: + pass + with conn: + Thread(target=send_loop, daemon=True).start() + while True: + data = conn.recv(1) + if not data: break + if data != garbage_character and data: + for i in data: + recv_data.append(i) diff --git a/src/youandme/tor.py b/src/youandme/tor.py index 62dd265..95e7797 100644 --- a/src/youandme/tor.py +++ b/src/youandme/tor.py @@ -1,7 +1,7 @@ import stem.process -def launch_tor(control_port="1338", socks_port="1339"): +def launch_tor(control_port="1336", socks_port="1337"): control_port = str(control_port) socks_port = str(socks_port) stem.process.launch_tor_with_config( diff --git a/tests/test.py b/tests/test.py deleted file mode 100644 index 0d6f79c..0000000 --- a/tests/test.py +++ /dev/null @@ -1,7 +0,0 @@ -import unittest -class TestBasic(unittest.TestCase): - - def test_basic(self): - self.assertTrue(True) - -unittest.main() \ No newline at end of file diff --git a/tests/test_client.py b/tests/test_client.py new file mode 100644 index 0000000..8984885 --- /dev/null +++ b/tests/test_client.py @@ -0,0 +1,42 @@ +import unittest +import socket +from threading import Thread +import time +import stem +import stem.process +from stem.control import Controller +from youandme import client + +control_port = str(1353) +socks_port = str(1354) + +stem.process.launch_tor_with_config( +config = { + 'ControlPort': control_port, + 'SocksPort': socks_port, + 'Log': [ + 'NOTICE stdout' + ], +}, take_ownership=True) + +def send_test_data(ip, port): + time.sleep(2) + s = socket.socket() + s.connect(('127.0.0.1', port)) + while True: + s.send(b"test") + for c in b"test2": + try: + s.send(chr(c).encode('utf8')) + except TypeError: + print(c) + s.close() + +class TestClient(unittest.TestCase): + + def test_client(self): + send_data = bytearray() + recv_data = bytearray() + #client(1, ) + +unittest.main() \ No newline at end of file diff --git a/tests/test_server.py b/tests/test_server.py new file mode 100644 index 0000000..1085a3e --- /dev/null +++ b/tests/test_server.py @@ -0,0 +1,79 @@ +import unittest +import socket +from threading import Thread +import time +import stem +import stem.process +from stem.control import Controller +from youandme import server + +control_port = str(1353) +socks_port = str(1354) + +stem.process.launch_tor_with_config( +config = { + 'ControlPort': control_port, + 'SocksPort': socks_port, + 'Log': [ + 'NOTICE stdout' + ], +}, take_ownership=True) + +def send_test_data(ip, port): + time.sleep(2) + s = socket.socket() + s.connect(('127.0.0.1', port)) + while True: + s.send(b"test") + for c in b"test2": + try: + s.send(chr(c).encode('utf8')) + except TypeError: + print(c) + s.close() + +class TestServer(unittest.TestCase): + + def test_server(self): + send_data = bytearray() + recv_data = bytearray() + with Controller.from_port(port=int(control_port)) as controller: + controller.authenticate() + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + ip = '127.0.0.1' + s.bind((ip, 0)) + s.listen(1) + port = s.getsockname()[1] + print(port) + serv = controller.create_ephemeral_hidden_service( + {1337: f'{ip}:{port}'}, + key_content='ED25519-V3', + await_publication=True, + ) + Thread(target=send_test_data, args=[ip, port], daemon=True).start() + conn, addr = s.accept() + Thread(target=server, args=[0.1, controller, conn, send_data, recv_data], daemon=True).start() + time.sleep(1) + max_iters = 10000000 + c = 0 + tested = False + filler_rec = False + while True: + c += 1 + if c >= max_iters: + break + try: + char = chr(recv_data.pop(0)).encode('utf8') + if char != b'\n': + tested = True + self.assertIn(char, b"testtest2") + except IndexError: + pass + else: + pass + if send_data: + print(send_data) + if not tested: + raise ValueError('not tested') + +unittest.main() \ No newline at end of file