From 9692fce5b2e2d5cc5bd7d2b13b46ab067f29b3dc Mon Sep 17 00:00:00 2001 From: Akilan Date: Thu, 2 Jan 2025 01:27:07 +0000 Subject: [PATCH] added python reference implementation --- python/.gitignore | 3 + python/SamplePythonTestServer/killserver.sh | 1 + python/SamplePythonTestServer/server.sh | 1 + python/library.py | 135 ++++++++++++++++++++ python/requirements.txt | 1 + python/test.py | 43 +++++++ 6 files changed, 184 insertions(+) create mode 100644 python/.gitignore create mode 100644 python/SamplePythonTestServer/killserver.sh create mode 100644 python/SamplePythonTestServer/server.sh create mode 100644 python/library.py create mode 100644 python/requirements.txt create mode 100644 python/test.py diff --git a/python/.gitignore b/python/.gitignore new file mode 100644 index 0000000..b63d853 --- /dev/null +++ b/python/.gitignore @@ -0,0 +1,3 @@ +p2prc-virtualenv/ +SharedObjects/ +__pycache__/ diff --git a/python/SamplePythonTestServer/killserver.sh b/python/SamplePythonTestServer/killserver.sh new file mode 100644 index 0000000..5275b4d --- /dev/null +++ b/python/SamplePythonTestServer/killserver.sh @@ -0,0 +1 @@ +lsof -i tcp:8084 | awk 'NR!=1 {print $2}' | xargs kill \ No newline at end of file diff --git a/python/SamplePythonTestServer/server.sh b/python/SamplePythonTestServer/server.sh new file mode 100644 index 0000000..a010623 --- /dev/null +++ b/python/SamplePythonTestServer/server.sh @@ -0,0 +1 @@ +python3 -m http.server 8084 \ No newline at end of file diff --git a/python/library.py b/python/library.py new file mode 100644 index 0000000..5cd1004 --- /dev/null +++ b/python/library.py @@ -0,0 +1,135 @@ +import ctypes +from ctypes import Structure, c_char_p, c_int, cdll +from dataclasses import dataclass, astuple +import time +import json +from urllib.parse import urlparse +from typing import List +import subprocess +import uuid +import dacite +import os + +p2prc = ctypes.CDLL("SharedObjects/p2prc.so") + +p2prc.Init("") + +# Global variable +# A global variable will be populated on runtime. +# It is read from P2PRC directly or from a local +# database. + +# Node information +# Generated using: https://jsonformatter.org/json-to-python +@dataclass +class Node: + Name: str + MachineUsername: str + IPV4: str + IPV6: str + Latency: int + Download: int + Upload: int + ServerPort: str + BareMetalSSHPort: str + NAT: str + EscapeImplementation: str + ProxyServer: str + UnSafeMode: bool + PublicKey: str + CustomInformation: str + +@dataclass +class IPAddress: + ip_address: List[Node] + + +# ---------------------------------------------------------------------------- +# ----------------------------- Helper functions ----------------------------- +# ---------------------------------------------------------------------------- + +def StartServer(): + # Starting P2PRC as a server mode + p2prc.Server() + for _ in iter(int, 1): + pass + +# Class to create string to pass as string function +# parameter to shared object file +class go_string(Structure): + _fields_ = [ + ("p", c_char_p), + ("n", c_int)] + +# Local port intended to ensure that +def P2PRCMapPort(port="",domainname="",serveraddress=""): + # Local Port intended to be escaped outside NAT + # Converting to the appropirate datatype to be + # passed as a string to GoLang. + port = go_string(c_char_p(port.encode('utf-8')), len(port)) + domainname = go_string(c_char_p(domainname.encode('utf-8')), len(domainname)) + serveraddress = go_string(c_char_p(serveraddress.encode('utf-8')), len(serveraddress)) + + # Defining the response type of the GoLang function + # function + p2prc.MapPort.restype = c_char_p + # Calling the Go function + address = p2prc.MapPort(port,domainname,serveraddress) + res = str(address).strip("b'") + return res + +def ListNodes(): + # View IP Table information + p2prc.ViewIPTable.restype = c_char_p + ipTable = p2prc.ViewIPTable() + # View IP Table as + ipTableObject = json.loads((str(ipTable).strip("b'"))) + dat: IPAddress = dacite.from_dict(IPAddress,ipTableObject) + return dat + +# ----------------------------------------------------------------------------------- +# ----------------------------- End of helper functions ----------------------------- +# ----------------------------------------------------------------------------------- + +def infinity(): + while True: + yield + +# Process datatype +@dataclass +class Process: + ID: str + InternalPortNo: str + ExternalAddress: str + NodeInfo: Node + TaskName: str + CommandToRunScript: str + CommandToKillScript: str + Status: bool + DomainName: str + +# Initial defined functions +# Exposed functions +def SpinProcess(process: Process): + # Starts P2PRC process + os.system(process.CommandToRunScript) + + process.ExternalAddress = P2PRCMapPort(port=process.InternalPortNo,domainname=process.DomainName,serveraddress=process.NodeInfo.ip_address.IPV4 + ":" + process.NodeInfo.ip_address.ServerPort) + process.ID = str(uuid.uuid4()) + process.Status = True + return process + +# Kill process based on the process provided +def KillProcess(process: Process): + os.system(process.CommandToKillScript) + process.Status = False + return process + + +# def ProcessInformation(): + +# def ListProcess(): + + + + \ No newline at end of file diff --git a/python/requirements.txt b/python/requirements.txt new file mode 100644 index 0000000..5b78deb --- /dev/null +++ b/python/requirements.txt @@ -0,0 +1 @@ +dacite \ No newline at end of file diff --git a/python/test.py b/python/test.py new file mode 100644 index 0000000..e463a47 --- /dev/null +++ b/python/test.py @@ -0,0 +1,43 @@ +from library import * + + +if __name__ == "__main__": + P2PRCNodes = ListNodes() + + # Create sample process + sample_process = Process( + ID="", + TaskName="TestServer", + InternalPortNo="8084", + NodeInfo=IPAddress(P2PRCNodes.ip_address[2]), + CommandToRunScript="sh SamplePythonTestServer/server.sh &", + CommandToKillScript="sh SamplePythonTestServer/killserver.sh", + DomainName="", + Status=False, + ExternalAddress="" + ) + + print("------------ Starting process -------------") + + # Spin process + sample_process = SpinProcess(sample_process) + + print("------------ Process Public address -------------") + + # Prints status of the current process + print(sample_process.ExternalAddress) + + print("------------ Process kept waiting for 20 seconds -------------") + + # Runs the process for 20 seconds + time.sleep(20) + + print("------------ Process getting killed -------------") + + # Kills the process + KillProcess(sample_process) + + print("------------ Process current process -------------") + + # Prints process status + print(sample_process.Status) \ No newline at end of file