Skip to content

Commit b6d92e5

Browse files
authored
Add files via upload
1 parent 734e71c commit b6d92e5

11 files changed

Lines changed: 950 additions & 0 deletions

File tree

core/__init__.py

Whitespace-only changes.

core/listener.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import socket
2+
import threading
3+
from typing import Callable, Optional
4+
5+
from core.session_manager import SessionManager
6+
from interface.colors import Colors
7+
8+
BIND_HOST = '0.0.0.0'
9+
10+
11+
class Listener(threading.Thread):
12+
def __init__(
13+
self,
14+
host: str,
15+
port: int,
16+
session_manager: SessionManager,
17+
on_connect: Optional[Callable[[int, str, int], None]] = None,
18+
):
19+
super().__init__(daemon=True)
20+
self.host = host
21+
self.port = port
22+
self.session_manager = session_manager
23+
self.on_connect = on_connect
24+
self._running = False
25+
self._server_socket: Optional[socket.socket] = None
26+
27+
def run(self) -> None:
28+
self._running = True
29+
self._server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
30+
self._server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
31+
32+
try:
33+
self._server_socket.bind((BIND_HOST, self.port))
34+
self._server_socket.listen(10)
35+
print(
36+
f"\n{Colors.success(f'[*] Listener started — binding {BIND_HOST}:{self.port}, payload LHOST: {self.host}')}"
37+
)
38+
print(Colors.dim(f" Waiting for incoming connections...\n"))
39+
40+
while self._running:
41+
try:
42+
self._server_socket.settimeout(1.0)
43+
conn, addr = self._server_socket.accept()
44+
session_id = self.session_manager.add_session(conn, addr)
45+
print(
46+
f"\n{Colors.bold(Colors.GREEN + '[+]' + Colors.ENDC)} "
47+
f"New connection from {Colors.info(addr[0])}:{Colors.warn(str(addr[1]))} "
48+
f"— {Colors.bold('Session ID:')} {Colors.success(str(session_id))}"
49+
)
50+
if self.on_connect:
51+
self.on_connect(session_id, addr[0], addr[1])
52+
except socket.timeout:
53+
continue
54+
except OSError:
55+
break
56+
except Exception as exc:
57+
print(Colors.error(f"[!] Listener error: {exc}"))
58+
finally:
59+
if self._server_socket:
60+
try:
61+
self._server_socket.close()
62+
except Exception:
63+
pass
64+
65+
def stop(self) -> None:
66+
self._running = False
67+
if self._server_socket:
68+
try:
69+
self._server_socket.close()
70+
except Exception:
71+
pass
72+
73+
@property
74+
def is_running(self) -> bool:
75+
return self._running and self.is_alive()

core/session_manager.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import socket
2+
import threading
3+
from typing import Any, Dict, List, Optional
4+
5+
6+
class Session:
7+
def __init__(self, session_id: int, conn: socket.socket, addr: tuple):
8+
self.id = session_id
9+
self.conn = conn
10+
self.addr = addr
11+
self.ip: str = addr[0]
12+
self.port: int = addr[1]
13+
14+
def send(self, data: str) -> None:
15+
self.conn.sendall((data + '\n').encode())
16+
17+
def recv(self, timeout: float = 3.0) -> str:
18+
self.conn.settimeout(timeout)
19+
response = b''
20+
try:
21+
while True:
22+
chunk = self.conn.recv(4096)
23+
if not chunk:
24+
break
25+
response += chunk
26+
except Exception:
27+
pass
28+
finally:
29+
self.conn.settimeout(None)
30+
return response.decode(errors='replace')
31+
32+
def close(self) -> None:
33+
try:
34+
self.conn.close()
35+
except Exception:
36+
pass
37+
38+
39+
class SessionManager:
40+
def __init__(self):
41+
self._sessions: Dict[int, Session] = {}
42+
self._counter: int = 0
43+
self._lock = threading.Lock()
44+
45+
def add_session(self, conn: socket.socket, addr: tuple) -> int:
46+
with self._lock:
47+
session_id = self._counter
48+
self._sessions[session_id] = Session(session_id, conn, addr)
49+
self._counter += 1
50+
return session_id
51+
52+
def get_session(self, session_id: int) -> Optional[Session]:
53+
with self._lock:
54+
return self._sessions.get(session_id)
55+
56+
def remove_session(self, session_id: int) -> None:
57+
with self._lock:
58+
if session_id in self._sessions:
59+
self._sessions[session_id].close()
60+
del self._sessions[session_id]
61+
62+
def list_sessions(self) -> List[Session]:
63+
with self._lock:
64+
return list(self._sessions.values())
65+
66+
def close_all(self) -> None:
67+
with self._lock:
68+
for session in self._sessions.values():
69+
session.close()
70+
self._sessions.clear()

core/utils.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import ipaddress
2+
import random
3+
import socket
4+
from typing import Dict
5+
6+
import psutil
7+
8+
9+
def get_network_interfaces() -> Dict[str, str]:
10+
interfaces: Dict[str, str] = {}
11+
12+
for iface, addrs in psutil.net_if_addrs().items():
13+
for addr in addrs:
14+
if addr.family == socket.AF_INET:
15+
try:
16+
ipaddress.ip_address(addr.address)
17+
interfaces[iface] = addr.address
18+
break
19+
except ValueError:
20+
continue
21+
22+
if not interfaces:
23+
try:
24+
ip = socket.gethostbyname(socket.gethostname())
25+
interfaces['eth0'] = ip
26+
except Exception:
27+
interfaces['lo'] = '127.0.0.1'
28+
29+
return interfaces
30+
31+
32+
def get_random_port() -> int:
33+
while True:
34+
port = random.randint(1024, 65535)
35+
try:
36+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
37+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
38+
sock.bind(('', port))
39+
return port
40+
except OSError:
41+
continue
42+
43+
44+
def is_valid_ip(ip: str) -> bool:
45+
try:
46+
ipaddress.ip_address(ip)
47+
return True
48+
except ValueError:
49+
return False
50+
51+
52+
def is_valid_port(port: str) -> bool:
53+
try:
54+
p = int(port)
55+
return 1 <= p <= 65535
56+
except ValueError:
57+
return False

interface/__init__.py

Whitespace-only changes.

interface/colors.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
class Colors:
2+
HEADER = '\033[95m'
3+
BLUE = '\033[94m'
4+
CYAN = '\033[96m'
5+
GREEN = '\033[92m'
6+
WARNING = '\033[93m'
7+
FAIL = '\033[91m'
8+
ENDC = '\033[0m'
9+
BOLD = '\033[1m'
10+
DIM = '\033[2m'
11+
UNDERLINE = '\033[4m'
12+
13+
@classmethod
14+
def success(cls, text: str) -> str:
15+
return f"{cls.GREEN}{text}{cls.ENDC}"
16+
17+
@classmethod
18+
def error(cls, text: str) -> str:
19+
return f"{cls.FAIL}{text}{cls.ENDC}"
20+
21+
@classmethod
22+
def warn(cls, text: str) -> str:
23+
return f"{cls.WARNING}{text}{cls.ENDC}"
24+
25+
@classmethod
26+
def info(cls, text: str) -> str:
27+
return f"{cls.CYAN}{text}{cls.ENDC}"
28+
29+
@classmethod
30+
def bold(cls, text: str) -> str:
31+
return f"{cls.BOLD}{text}{cls.ENDC}"
32+
33+
@classmethod
34+
def dim(cls, text: str) -> str:
35+
return f"{cls.DIM}{text}{cls.ENDC}"

0 commit comments

Comments
 (0)