Commit 9ad2eae8 authored by ibuler's avatar ibuler

添加监控记录

parent ba26608a
...@@ -29,6 +29,7 @@ class Coco: ...@@ -29,6 +29,7 @@ class Coco:
'SECRET_KEY': None, 'SECRET_KEY': None,
'LOG_LEVEL': 'INFO', 'LOG_LEVEL': 'INFO',
'LOG_DIR': os.path.join(BASE_DIR, 'logs'), 'LOG_DIR': os.path.join(BASE_DIR, 'logs'),
'SESSION_DIR': os.path.join(BASE_DIR, 'sessions'),
'ASSET_SORT_BY': 'hostname', # hostname, ip 'ASSET_SORT_BY': 'hostname', # hostname, ip
'SSH_PASSWORD_AUTH': True, 'SSH_PASSWORD_AUTH': True,
'SSH_PUBLIC_KEY_AUTH': True, 'SSH_PUBLIC_KEY_AUTH': True,
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
import socket import socket
import threading import threading
import logging
import paramiko import paramiko
...@@ -10,6 +11,9 @@ from .models import Server ...@@ -10,6 +11,9 @@ from .models import Server
from .exception import PermissionFailed from .exception import PermissionFailed
logger = logging.getLogger(__file__)
class ProxyServer: class ProxyServer:
def __init__(self, app, client, request): def __init__(self, app, client, request):
self.app = app self.app = app
...@@ -21,12 +25,13 @@ class ProxyServer: ...@@ -21,12 +25,13 @@ class ProxyServer:
try: try:
self.server = self.get_server_conn(asset, system_user) self.server = self.get_server_conn(asset, system_user)
except PermissionFailed: except PermissionFailed:
self.client.send("No permission") self.client.send(b"No permission")
return return
session = Session(self.client, self.server) session = Session(self.client, self.server)
self.app.sessions.append(session) self.app.sessions.append(session)
self.watch_win_size_change_async() self.watch_win_size_change_async()
session.record_async()
session.bridge() session.bridge()
self.app.sessions.remove(session) self.app.sessions.remove(session)
...@@ -57,11 +62,11 @@ class ProxyServer: ...@@ -57,11 +62,11 @@ class ProxyServer:
password=system_user.password, password=system_user.password,
pkey=system_user.private_key) pkey=system_user.private_key)
except paramiko.AuthenticationException as e: except paramiko.AuthenticationException as e:
self.client.send("Authentication failed: %s" % e) self.client.send(b"Authentication failed: %s" % e)
return return
except socket.error as e: except socket.error as e:
self.client.send("Connection server error: %s" % e) self.client.send(b"Connection server error: %s" % e)
return return
term = self.request.meta.get('term', 'xterm') term = self.request.meta.get('term', 'xterm')
...@@ -75,7 +80,7 @@ class ProxyServer: ...@@ -75,7 +80,7 @@ class ProxyServer:
self.request.change_size_event.clear() self.request.change_size_event.clear()
width = self.request.meta.get('width', 80) width = self.request.meta.get('width', 80)
height = self.request.meta.get('height', 24) height = self.request.meta.get('height', 24)
print("Change win size: %s - %s" % (width, height)) logger.debug("Change win size: %s - %s" % (width, height))
self.server.chan.resize_pty(width=width, height=height) self.server.chan.resize_pty(width=width, height=height)
def watch_win_size_change_async(self): def watch_win_size_change_async(self):
......
...@@ -126,8 +126,8 @@ class Server: ...@@ -126,8 +126,8 @@ class Server:
return getattr(self.chan, item) return getattr(self.chan, item)
def __str__(self): def __str__(self):
return "<%s@%s:%s>" % \ return "<%s@%s:%s>" % (self.system_user.username,
(self.system_user.username, self.asset.hostname, self.asset.port) self.asset.hostname, self.asset.port)
class WSProxy: class WSProxy:
......
#!coding: utf-8 #!coding: utf-8
import select import os
import threading
import uuid import uuid
import socket import socket
import logging import logging
import datetime import datetime
import time
import selectors import selectors
...@@ -14,10 +16,11 @@ logger = logging.getLogger(__file__) ...@@ -14,10 +16,11 @@ logger = logging.getLogger(__file__)
class Session: class Session:
def __init__(self, client, server): def __init__(self, client, server, record_dir="/tmp"):
self.id = str(uuid.uuid4()) self.id = str(uuid.uuid4())
self.client = client # Master of the session, it's a client sock self.client = client # Master of the session, it's a client sock
self.server = server # Server channel self.server = server # Server channel
self.record_dir = record_dir # Dir to save session record
self.watchers = [] # Only watch session self.watchers = [] # Only watch session
self.sharers = [] # Join to the session, read and write self.sharers = [] # Join to the session, read and write
self.running = True self.running = True
...@@ -25,38 +28,43 @@ class Session: ...@@ -25,38 +28,43 @@ class Session:
self.date_finished = None self.date_finished = None
self.sel = selectors.DefaultSelector() self.sel = selectors.DefaultSelector()
def add_watcher(self, watcher): def add_watcher(self, watcher, silent=False):
""" """
Add a watcher, and will be transport server side msg to it. Add a watcher, and will be transport server side msg to it.
:param watcher: A client socket :param watcher: A client socket
:param silent: If true not send welcome message
:return: :return:
""" """
logger.info("Session % add watcher %s" % (self, watcher)) logger.info("Session % add watcher %s" % (self, watcher))
watcher.send("Welcome to join session %s\r\n" % self.id) if not silent:
watcher.send("Welcome to watch session {}\r\n".format(self.id).encode("utf-8"))
self.sel.register(watcher, selectors.EVENT_READ) self.sel.register(watcher, selectors.EVENT_READ)
self.watchers.append(watcher) self.watchers.append(watcher)
def remove_watcher(self, watcher): def remove_watcher(self, watcher):
logger.info("Session %s remove watcher %s" % (self, watcher)) logger.info("Session %s remove watcher %s" % (self, watcher))
watcher.send("Leave session %s at %s" % (self.id, datetime.datetime.now()))
self.sel.unregister(watcher) self.sel.unregister(watcher)
self.watchers.remove(watcher) self.watchers.remove(watcher)
def add_sharer(self, sharer): def add_sharer(self, sharer, silent=False):
""" """
Add a sharer, it can read and write to server Add a sharer, it can read and write to server
:param sharer: A client socket :param sharer: A client socket
:param silent: If true not send welcome message
:return: :return:
""" """
logger.info("Session %s add share %s" % (self.id, sharer)) logger.info("Session %s add share %s" % (self.id, sharer))
sharer.send("Welcome to join session %s\r\n" % self.id) if not silent:
sharer.send("Welcome to join session {}\r\n"
.format(self.id).encode("utf-8"))
self.sel.register(sharer, selectors.EVENT_READ) self.sel.register(sharer, selectors.EVENT_READ)
self.sharers.append(sharer) self.sharers.append(sharer)
def remove_sharer(self, sharer): def remove_sharer(self, sharer):
logger.info("Session %s remove sharer %s" % (self.id, sharer)) logger.info("Session %s remove sharer %s" % (self.id, sharer))
sharer.send("Leave session %s at %s" % (self.id, datetime.datetime.now())) sharer.send("Leave session {} at {}"
.format(self.id, datetime.datetime.now()).encode("utf-8"))
self.sel.unregister(sharer) self.sel.unregister(sharer)
self.sharers.remove(sharer) self.sharers.remove(sharer)
...@@ -105,14 +113,42 @@ class Session: ...@@ -105,14 +113,42 @@ class Session:
""" """
parent, child = socket.socketpair() parent, child = socket.socketpair()
self.add_watcher(parent) self.add_watcher(parent)
with open(os.path.join(self.record_dir, self.id + ".rec"), 'wb') as screenf, \
open(os.path.join(self.record_dir, self.id + ".time"), "w") as timef:
screenf.write("Script started on {}\n".format(time.asctime()).encode("utf-8"))
while self.running:
start_t = time.time()
data = child.recv(BUF_SIZE)
end_t = time.time()
size = len(data)
if size == 0:
break
timef.write("%.4f %s\n" % (end_t-start_t, size))
screenf.write(data)
print("Pass %.4f, print %d" % (end_t-start_t, size))
print("Data: {}".format(data.decode('utf-8')))
screenf.write("Script done on {}\n".format(time.asctime()).encode("utf-8"))
def record_async(self):
thread = threading.Thread(target=self.record)
thread.daemon = True
thread.start()
def replay(self): def replay(self):
"""
Replay the session
:return:
"""
pass
def replay_down(self):
pass pass
def close(self): def close(self):
self.running = False self.running = False
self.server.close() for chan in [self.client, self.server] + self.watchers + self.sharers:
return chan.close()
def __str__(self): def __str__(self):
return self.id return self.id
......
...@@ -36,6 +36,9 @@ APP_NAME = "coco" ...@@ -36,6 +36,9 @@ APP_NAME = "coco"
# 日志存放的目录 # 日志存放的目录
# LOG_DIR = os.path.join(BASE_DIR, 'logs') # LOG_DIR = os.path.join(BASE_DIR, 'logs')
# Session录像存放目录
# SESSION_DIR = os.path.join(BASE_DIR, 'sessions')
# 资产显示排序方式, ['ip', 'hostname'] # 资产显示排序方式, ['ip', 'hostname']
# ASSET_LIST_SORT_BY = 'ip' # ASSET_LIST_SORT_BY = 'ip'
......
...@@ -15,6 +15,7 @@ except ImportError: ...@@ -15,6 +15,7 @@ except ImportError:
try: try:
os.mkdir("logs") os.mkdir("logs")
os.mkdir("keys") os.mkdir("keys")
os.mkdir("sessions")
except: except:
pass pass
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment