summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhc <hc@email.ch>2025-02-01 10:21:49 +0800
committerhc <hc@email.ch>2025-02-01 10:21:49 +0800
commit6e2bd1f5053f5244d1294ba5ae2c0ffc047743b6 (patch)
treefb1d970b1f952eb372a19d51e360e62c64d36ec6
firstcommit
-rw-r--r--client_ls.py21
-rw-r--r--client_manager.py140
-rw-r--r--sys_init.py49
3 files changed, 210 insertions, 0 deletions
diff --git a/client_ls.py b/client_ls.py
new file mode 100644
index 0000000..6aa3a7e
--- /dev/null
+++ b/client_ls.py
@@ -0,0 +1,21 @@
1
2#lists client information
3
4import fcntl
5import json
6import os
7
8
9def read_data():
10 try:
11 with open('/tmp/ssh_sessions.json', 'r') as f:
12 # Get shared lock for reading
13 fcntl.flock(f.fileno(), fcntl.LOCK_SH)
14 try:
15 return json.load(f)
16 finally:
17 fcntl.flock(f.fileno(), fcntl.LOCK_UN)
18 except (FileNotFoundError, ValueError):
19 return {}
20
21print(read_data())
diff --git a/client_manager.py b/client_manager.py
new file mode 100644
index 0000000..84bf3df
--- /dev/null
+++ b/client_manager.py
@@ -0,0 +1,140 @@
1
2# main logic
3
4from sys_init import setup
5setup()
6
7import pyinotify
8import subprocess
9import re
10import pwd
11import os
12import json
13import atexit
14import fcntl
15
16def get_ssh_port(pid):
17 '''
18 Jan 31 07:50:28 vultr sshd[43690]: Accepted publickey for root from 210.10.76.5 port 43730 ssh2: ED25519 SHA256:qz9ffMCb3vPlabn3ZHee00qIPBxkDiUiVSorcUkGdII
19 Jan 31 07:50:28 vultr sshd[43690]: pam_unix(sshd:session): session opened for user root(uid=0) by root(uid=0)
20 Jan 31 07:50:29 vultr sshd[43693]: Received disconnect from 210.10.76.5 port 43730:11: disconnected by user
21 Jan 31 07:50:29 vultr sshd[43693]: Disconnected from user root 210.10.76.5 port 43730
22 Jan 31 07:50:29 vultr sshd[43690]: pam_unix(sshd:session): session closed for user root
23 '''
24 '''
25 # less efficient but readable
26 pid = '33216'
27 pids = []
28 port = -1
29 for l in lines:
30 l = l.split()
31 if pid == l[1]:
32 commonstring = l[8]
33 for l2 in lines:
34 if commonstring in l2.split():
35 pids.append(l2.split()[1])
36 for i in pids:
37 for l in lines:
38 l = l.split()
39 if i in l[1] and "*:" in l[8]:
40 port = l[8][2:]
41 '''
42 try:
43 lines = subprocess.check_output("lsof -i -n | grep sshd", shell=True, text=True).splitlines()
44 pid = str(pid)
45 pids = {l.split()[1] for l in lines
46 if pid == l.split()[1] or
47 l.split()[8] in [x.split()[8] for x in lines if x.split()[1] == pid]}
48
49 port = next(l.split()[8][2:] for l in lines if l.split()[1] in pids and "*:" in l.split()[8])
50 return port
51 except:
52 return -1
53
54def get_keyname(fingerprint):
55 auth_file = os.path.join(os.path.expanduser(f"~{user}"), ".ssh", "authorized_keys")
56 try:
57 result = subprocess.run(['ssh-keygen', '-lf', f'{auth_file}'], capture_output=True, text=True, shell=False, check=True)
58 # Raises CalledProcessError if command fails, for check = true
59
60 #256 SHA256:d9CBxSLBLzLjYGZDCsO6V+lddlN/elK1hGDBS56cbTo user@host (ED25519)
61 for line in result.stdout.strip().split('\n'):
62 parts = line.split()
63 if fingerprint in parts[1]:
64 return parts[2]
65 return 'not found'
66
67 except subprocess.CalledProcessError as e:
68 print(f"Error executing command: {e}")
69 return None
70 except Exception as e:
71 print(f"Error processing output: {e}")
72 return None
73
74def write_data(data):
75 with open('/tmp/ssh_sessions.json', 'w') as f:
76 # Get exclusive lock for writing
77 fcntl.flock(f.fileno(), fcntl.LOCK_EX)
78 try:
79 # Clear file and write new data
80 f.seek(0)
81 json.dump(data, f)
82 f.truncate()
83 finally:
84 fcntl.flock(f.fileno(), fcntl.LOCK_UN)
85
86def handle_log_change(event):
87 global last_position
88 with open(event.pathname, 'r') as f:
89 # Go to end and read new lines
90 f.seek(last_position)
91 new_lines = f.readlines()
92 last_position = f.tell()
93
94 for line in new_lines:
95 #print(f"New log: {line.strip()}")
96 line = line.strip()
97 if f"Accepted publickey for {user}" in line:
98 pid = re.search(r'\[(\d+)\]', line.split()[4]).group(1)
99 port = get_ssh_port(pid)
100 keyname = get_keyname(line.split()[15])
101 srcip = line.split()[10]
102 #print(pid, port, keyname, srcip)
103 ssh_sessions[pid] = [srcip, keyname, port]
104 ssh_sessions[pid] = {
105 'srcip': srcip,
106 'key': keyname,
107 'pubport': port
108 }
109 write_data(ssh_sessions)
110 if "pam_unix(sshd:session): session closed" in line:
111 pid = re.search(r'\[(\d+)\]', line.split()[4]).group(1)
112 if pid in ssh_sessions:
113 del ssh_sessions[pid]
114 else:
115 print("WARNING! PID NOT FOUND IN SESSION CACHE!")
116 write_data(ssh_sessions)
117
118 print("db: ",ssh_sessions)
119
120
121
122user = "root"
123
124# init last_position
125global last_position
126with open('/var/log/secure', 'r') as f:
127 f.seek(0, 2)
128 last_position = f.tell()
129
130global ssh_sessions
131ssh_sessions = {}
132
133wm = pyinotify.WatchManager()
134wm.add_watch('/var/log/secure', pyinotify.IN_MODIFY, handle_log_change)
135notifier = pyinotify.Notifier(wm)
136
137print("Watching /var/log/secure...")
138notifier.loop()
139
140
diff --git a/sys_init.py b/sys_init.py
new file mode 100644
index 0000000..5bcd618
--- /dev/null
+++ b/sys_init.py
@@ -0,0 +1,49 @@
1
2#installs pip packages and lsof for debian
3
4import subprocess
5import sys
6import os
7import importlib
8
9def check_os():
10 if os.path.exists('/etc/os-release'):
11 with open('/etc/os-release', 'r') as f:
12 content = f.read().lower()
13 if 'debian' in content or 'ubuntu' in content:
14 return 'debian'
15 elif 'fedora' in content:
16 return 'fedora'
17 return None
18
19def install_package(package):
20 try:
21 importlib.import_module(package)
22 print(f"{package} is already installed")
23 except ImportError:
24 try:
25 subprocess.check_call([sys.executable, "-m", "pip", "install", package])
26 print(f"Successfully installed {package}")
27 except subprocess.CalledProcessError:
28 print(f"Failed to install {package}")
29
30def install_lsof():
31 os_type = check_os()
32 if os_type == 'debian':
33 try:
34 subprocess.check_call(['apt-get', 'update'])
35 subprocess.check_call(['apt-get', 'install', '-y', 'lsof'])
36 print("lsof installed successfully")
37 except subprocess.CalledProcessError:
38 print("Failed to install lsof")
39 else:
40 print("Not a Debian-based system, skipping lsof installation")
41
42def setup():
43 # Install pyinotify
44 install_package('pyinotify')
45 # Install lsof if on Debian
46 install_lsof()
47
48if __name__ == "__main__":
49 setup()