Commit 2467b4e2 authored by 广宏伟's avatar 广宏伟

Merged in dev (pull request #57)

Dev
parents 4d2015df 01285f53
...@@ -219,13 +219,19 @@ class Coco: ...@@ -219,13 +219,19 @@ class Coco:
def add_client(self, client): def add_client(self, client):
with self.lock: with self.lock:
self.clients.append(client) self.clients.append(client)
logger.info("New client {} join, total {} now".format(client, len(self.clients))) logger.info("New client {} join, total {} now".format(
client, len(self.clients)
)
)
def remove_client(self, client): def remove_client(self, client):
with self.lock: with self.lock:
try: try:
self.clients.remove(client) self.clients.remove(client)
logger.info("Client {} leave, total {} now".format(client, len(self.clients))) logger.info("Client {} leave, total {} now".format(
client, len(self.clients)
)
)
client.close() client.close()
except: except:
pass pass
...@@ -242,4 +248,5 @@ class Coco: ...@@ -242,4 +248,5 @@ class Coco:
self.sessions.remove(session) self.sessions.remove(session)
self.service.finish_session(session.to_json()) self.service.finish_session(session.to_json())
except ValueError: except ValueError:
logger.warning("Remove session: {} fail, maybe already removed".format(session)) msg = "Remove session: {} fail, maybe already removed"
\ No newline at end of file logger.warning(msg.format(session))
...@@ -34,7 +34,7 @@ class SSHConnection: ...@@ -34,7 +34,7 @@ class SSHConnection:
self.get_system_user_auth(system_user) self.get_system_user_auth(system_user)
if asset.domain: if asset.domain:
sock = self.get_proxy_sock(asset) sock = self.get_proxy_sock_v2(asset)
try: try:
ssh.connect( ssh.connect(
...@@ -64,29 +64,54 @@ class SSHConnection: ...@@ -64,29 +64,54 @@ class SSHConnection:
return None, str(e) return None, str(e)
except (socket.error, TimeoutError) as e: except (socket.error, TimeoutError) as e:
return None, str(e) return None, str(e)
return ssh, None return ssh, sock, None
def get_transport(self, asset, system_user): def get_transport(self, asset, system_user):
ssh, msg = self.get_ssh_client(asset, system_user) ssh, sock, msg = self.get_ssh_client(asset, system_user)
if ssh: if ssh:
return ssh.get_transport(), None return ssh.get_transport(), sock, None
else: else:
return None, msg return None, None, msg
def get_channel(self, asset, system_user, term="xterm", width=80, height=24): def get_channel(self, asset, system_user, term="xterm", width=80, height=24):
ssh, msg = self.get_ssh_client(asset, system_user) ssh, sock, msg = self.get_ssh_client(asset, system_user)
if ssh: if ssh:
chan = ssh.invoke_shell(term, width=width, height=height) chan = ssh.invoke_shell(term, width=width, height=height)
return chan, None return chan, sock, None
else: else:
return None, msg return None, sock, msg
def get_sftp(self, asset, system_user): def get_sftp(self, asset, system_user):
ssh, msg = self.get_ssh_client(asset, system_user) ssh, sock, msg = self.get_ssh_client(asset, system_user)
if ssh: if ssh:
return ssh.open_sftp(), None return ssh.open_sftp(), sock, None
else: else:
return None, msg return None, sock, msg
def get_proxy_sock_v2(self, asset):
sock = None
domain = app_service.get_domain_detail_with_gateway(
asset.domain
)
if not domain.has_ssh_gateway():
return None
for i in domain.gateways:
gateway = domain.random_ssh_gateway()
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh.connect(gateway.ip, username=gateway.username,
password=gateway.password,
pkey=gateway.private_key_obj)
except(paramiko.AuthenticationException,
paramiko.BadAuthenticationType,
SSHException):
continue
sock = ssh.get_transport().open_channel(
'direct-tcpip', (asset.ip, asset.port), ('127.0.0.1', 0)
)
break
return sock
def get_proxy_sock(self, asset): def get_proxy_sock(self, asset):
sock = None sock = None
......
...@@ -212,8 +212,7 @@ class ProxyNamespace(BaseNamespace): ...@@ -212,8 +212,7 @@ class ProxyNamespace(BaseNamespace):
def on_disconnect(self): def on_disconnect(self):
logger.debug("On disconnect event trigger") logger.debug("On disconnect event trigger")
room_id_list = list(self.connections.get(request.sid, {}).keys()) for room_id in self.connections.get(request.sid, {}):
for room_id in room_id_list:
try: try:
self.on_logout(room_id) self.on_logout(room_id)
except Exception as e: except Exception as e:
...@@ -250,14 +249,14 @@ class HttpServer: ...@@ -250,14 +249,14 @@ class HttpServer:
self.flask_app.config.update(config) self.flask_app.config.update(config)
self.socket_io = SocketIO() self.socket_io = SocketIO()
self.register_routes() self.register_routes()
self.register_error_handler()
def register_routes(self): def register_routes(self):
self.socket_io.on_namespace(ProxyNamespace('/ssh')) self.socket_io.on_namespace(ProxyNamespace('/ssh'))
@staticmethod @staticmethod
def on_error_default(e): def on_error_default(e):
traceback.print_exc() logger.exception(e)
logger.warn(e)
def register_error_handler(self): def register_error_handler(self):
self.socket_io.on_error_default(self.on_error_default) self.socket_io.on_error_default(self.on_error_default)
......
...@@ -263,7 +263,7 @@ class InteractiveServer: ...@@ -263,7 +263,7 @@ class InteractiveServer:
self.display_banner() self.display_banner()
while True: while True:
try: try:
opt = net_input(self.client, prompt='Opt>', before=1) opt = net_input(self.client, prompt='Opt> ', before=1)
rv = self.dispatch(opt) rv = self.dispatch(opt)
if rv is self._sentinel: if rv is self._sentinel:
break break
......
...@@ -94,8 +94,9 @@ class Server: ...@@ -94,8 +94,9 @@ class Server:
""" """
# Todo: Server name is not very suitable # Todo: Server name is not very suitable
def __init__(self, chan, asset, system_user): def __init__(self, chan, sock, asset, system_user):
self.chan = chan self.chan = chan
self.sock = sock
self.asset = asset self.asset = asset
self.system_user = system_user self.system_user = system_user
self.send_bytes = 0 self.send_bytes = 0
...@@ -168,6 +169,8 @@ class Server: ...@@ -168,6 +169,8 @@ class Server:
self.stop_evt.set() self.stop_evt.set()
self.chan.close() self.chan.close()
self.chan.transport.close() self.chan.transport.close()
if self.sock:
self.sock.transport.close()
@staticmethod @staticmethod
def _have_enter_char(s): def _have_enter_char(s):
...@@ -251,7 +254,6 @@ class WSProxy: ...@@ -251,7 +254,6 @@ class WSProxy:
if len(data) == 0: if len(data) == 0:
self.close() self.close()
data = data.decode(errors="ignore") data = data.decode(errors="ignore")
print("Send data: {}".format(data))
self.ws.emit("data", {'data': data, 'room': self.room_id}, self.ws.emit("data", {'data': data, 'room': self.room_id},
room=self.room_id) room=self.room_id)
if len(data) == BUF_SIZE: if len(data) == BUF_SIZE:
...@@ -264,8 +266,11 @@ class WSProxy: ...@@ -264,8 +266,11 @@ class WSProxy:
def close(self): def close(self):
self.stop_event.set() self.stop_event.set()
self.child.shutdown(1) try:
self.child.close() self.child.shutdown(1)
self.child.close()
except (OSError, EOFError):
pass
logger.debug("Proxy {} closed".format(self)) logger.debug("Proxy {} closed".format(self))
......
...@@ -90,14 +90,14 @@ class ProxyServer: ...@@ -90,14 +90,14 @@ class ProxyServer:
width = request.meta.get('width', 80) width = request.meta.get('width', 80)
height = request.meta.get('height', 24) height = request.meta.get('height', 24)
ssh = SSHConnection() ssh = SSHConnection()
chan, msg = ssh.get_channel( chan, sock, msg = ssh.get_channel(
asset, system_user, term=term, width=width, height=height asset, system_user, term=term, width=width, height=height
) )
if not chan: if not chan:
self.client.send(warning(wr(msg, before=1, after=0))) self.client.send(warning(wr(msg, before=1, after=0)))
server = None server = None
else: else:
server = Server(chan, asset, system_user) server = Server(chan, sock, asset, system_user)
self.connecting = False self.connecting = False
self.client.send(b'\r\n') self.client.send(b'\r\n')
return server return server
......
...@@ -2,6 +2,7 @@ import os ...@@ -2,6 +2,7 @@ import os
import tempfile import tempfile
import paramiko import paramiko
import time import time
from .ctx import app_service
from datetime import datetime from datetime import datetime
from .connection import SSHConnection from .connection import SSHConnection
...@@ -16,6 +17,17 @@ class SFTPServer(paramiko.SFTPServerInterface): ...@@ -16,6 +17,17 @@ class SFTPServer(paramiko.SFTPServerInterface):
self._sftp = {} self._sftp = {}
self.hosts = self.get_perm_hosts() self.hosts = self.get_perm_hosts()
def session_ended(self):
super().session_ended()
for _, v in self._sftp.items():
sftp = v['sftp']
sock = v.get('sock')
sftp.close()
if sock:
sock.close()
sock.transport.close()
self._sftp = {}
def get_host_sftp(self, host, su): def get_host_sftp(self, host, su):
asset = self.hosts.get(host) asset = self.hosts.get(host)
system_user = None system_user = None
...@@ -28,18 +40,18 @@ class SFTPServer(paramiko.SFTPServerInterface): ...@@ -28,18 +40,18 @@ class SFTPServer(paramiko.SFTPServerInterface):
raise OSError("No asset or system user explicit") raise OSError("No asset or system user explicit")
if host not in self._sftp: if host not in self._sftp:
ssh = SSHConnection(self.server.app) ssh = SSHConnection()
sftp, msg = ssh.get_sftp(asset, system_user) sftp, sock, msg = ssh.get_sftp(asset, system_user)
if sftp: if sftp:
self._sftp[host] = sftp self._sftp[host] = {'sftp': sftp, 'sock': sock}
return sftp return sftp
else: else:
raise OSError("Can not connect asset sftp server: {}".format(msg)) raise OSError("Can not connect asset sftp server: {}".format(msg))
else: else:
return self._sftp[host] return self._sftp[host]['sftp']
def get_perm_hosts(self): def get_perm_hosts(self):
assets = self.server.app.service.get_user_assets( assets = app_service.get_user_assets(
self.server.request.user self.server.request.user
) )
return {asset.hostname: asset for asset in assets} return {asset.hostname: asset for asset in assets}
...@@ -89,7 +101,7 @@ class SFTPServer(paramiko.SFTPServerInterface): ...@@ -89,7 +101,7 @@ class SFTPServer(paramiko.SFTPServerInterface):
"is_success": is_success, "is_success": is_success,
} }
for i in range(1, 4): for i in range(1, 4):
ok = self.server.app.service.create_ftp_log(data) ok = app_service.create_ftp_log(data)
if ok: if ok:
break break
else: else:
......
...@@ -396,7 +396,6 @@ def size_of_str_with_zh(s): ...@@ -396,7 +396,6 @@ def size_of_str_with_zh(s):
try: try:
chinese = find_chinese(s) chinese = find_chinese(s)
except TypeError: except TypeError:
print(type(s))
raise raise
return len(s) + len(chinese) return len(s) + len(chinese)
...@@ -406,6 +405,8 @@ def item_max_length(_iter, maxi=None, mini=None, key=None): ...@@ -406,6 +405,8 @@ def item_max_length(_iter, maxi=None, mini=None, key=None):
_iter = [key(i) for i in _iter] _iter = [key(i) for i in _iter]
length = [size_of_str_with_zh(s) for s in _iter] length = [size_of_str_with_zh(s) for s in _iter]
if not length:
return 1
if maxi: if maxi:
length.append(maxi) length.append(maxi)
length = max(length) length = max(length)
......
...@@ -20,7 +20,7 @@ Jinja2==2.10 ...@@ -20,7 +20,7 @@ Jinja2==2.10
jmespath==0.9.3 jmespath==0.9.3
jms-es-sdk==0.5.2 jms-es-sdk==0.5.2
jms-storage==0.0.12 jms-storage==0.0.12
jumpserver-python-sdk==0.0.41 jumpserver-python-sdk==0.0.42
MarkupSafe==1.0 MarkupSafe==1.0
oss2==2.4.0 oss2==2.4.0
paramiko==2.4.0 paramiko==2.4.0
......
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