def _get_core_server_config(self): cfg = tp_cfg() try: req = {'method': 'get_config', 'param': []} req_data = json.dumps(req) data = urllib.parse.quote(req_data).encode('utf-8') req = urllib.request.Request(url=cfg.common.core_server_rpc, data=data) rep = urllib.request.urlopen(req, timeout=3) body = rep.read().decode() x = json.loads(body) if 'code' not in x or x['code'] != 0: log.e('connect core-server for get config info failed.\n') else: cfg.update_core(x['data']) log.d('get config info of core-server succeeded.\n') except: log.w('can not connect to core-server to get config, maybe it not start yet, ignore.\n')
def get_fields(self, table_name): fields = list() if self.db_type == self.DB_TYPE_SQLITE: ret = self.query('PRAGMA table_info(`{}`);'.format(table_name)) log.d('[sqlite] fields of {}'.format(table_name), ret, '\n') if ret is None: return None for f in ret: fields.append((f[1], f[2])) # field_name, field_type, e.g.: ('id', 'integer'), ('desc', 'varchar(255)') elif self.db_type == self.DB_TYPE_MYSQL: ret = self.query('SELECT `column_name` FROM `information_schema`.`columns` WHERE `table_schema`="db" AND `table_name`="{}";'.format(table_name)) log.d('[mysql] fields of {}'.format(table_name), ret, '\n') if ret is None: return None for f in ret: fields.append(f) return fields
def _run_loop(self): ext_srv_cfg = tp_ext_srv_cfg() if not ext_srv_cfg.init(): return 0 log.i('Teleport Web Server starting ...\n') tp_cron().init() # 尝试通过CORE-JSON-RPC获取core服务的配置(主要是ssh/rdp/telnet的端口以及录像文件存放路径) self._get_core_server_config() _db = get_db() if not _db.init(): log.e('can not initialize database interface.\n') return 0 _db.connect() while not _db.connected: log.w('database not connected, retry after 5 seconds.\n') time.sleep(5) _db.connect() cfg = tp_cfg() _db.check_status() if _db.need_create or _db.need_upgrade: cfg.app_mode = APP_MODE_MAINTENANCE tp_cfg().update_sys(None) else: cfg.app_mode = APP_MODE_NORMAL _db.load_system_config() try: # 将运行时配置发送给核心服务 req = {'method': 'set_config', 'param': {'noop_timeout': tp_cfg().sys.session.noop_timeout}} req_data = json.dumps(req) data = urllib.parse.quote(req_data).encode('utf-8') req = urllib.request.Request(url=cfg.common.core_server_rpc, data=data) rep = urllib.request.urlopen(req, timeout=3) body = rep.read().decode() x = json.loads(body) if 'code' not in x or x['code'] != 0: print(x) log.e('connect core-server for set runtime-config failed.\n') else: log.d('set runtime-config for core-server succeeded.\n') except: log.w('can not connect to core-server to set runtime-config, maybe it not start yet, ignore.\n') if not tp_session().init(): log.e('can not initialize session manager.\n') return 0 if not tp_stats().init(): log.e('can not initialize system status collector.\n') return 0 if cfg.common.check_host_alive: if not tp_host_alive().init(): log.e('can not initialize host state inspector.\n') return 0 settings = { # 'cookie_secret': '8946svdABGD345fg98uhIaefEBePIfegOIakjFH43oETzK', 'login_url': '/auth/login', # 指定静态文件的路径,页面模板中可以用 {{ static_url('css/main.css') }} 的方式调用 'static_path': cfg.static_path, # 指定模板文件的路径 'template_path': cfg.template_path, # 防止跨站伪造请求,参见 http://old.sebug.net/paper/books/tornado/#_7 'xsrf_cookies': False, 'autoescape': 'xhtml_escape', # 'ui_modules': ui_modules, 'debug': False, # 不开启模板和静态文件的缓存,这样一旦模板文件和静态文件变化,刷新浏览器即可看到更新。 'compiled_template_cache': False, 'static_hash_cache': False, } from app.controller import controllers, fix_controller fix_controller() _app = tornado.web.Application(controllers, **settings) server = tornado.httpserver.HTTPServer(_app, xheaders=True) # server = tornado.httpserver.HTTPServer(_app, xheaders=True, ssl_options={ # "certfile": os.path.join(cfg.data_path, 'cert', "server.pem"), # "keyfile": os.path.join(cfg.data_path, 'cert', "server.key"), # }) try: server.listen(cfg.common.port, address=cfg.common.ip) if cfg.common.ip == '0.0.0.0': log.i('works on [http://127.0.0.1:{}]\n'.format(cfg.common.port)) else: log.i('works on [http://{}:{}]\n'.format(cfg.common.ip, cfg.common.port)) except: log.e('can not listen on port {}:{}, make sure it not been used by another application.\n'.format(cfg.common.ip, cfg.common.port)) return 0 # 启动定时任务调度器 tp_cron().start() try: tornado.ioloop.IOLoop.instance().start() except: log.e('\n') if tp_cfg().common.check_host_alive: tp_host_alive().stop() tp_cron().stop() return 0
def read_record_head(protocol_type, record_id): if not tp_cfg().core.detected: return None, TPE_NO_CORE_SERVER if protocol_type == TP_PROTOCOL_TYPE_RDP: path_name = 'rdp' elif protocol_type == TP_PROTOCOL_TYPE_SSH: path_name = 'ssh' elif protocol_type == TP_PROTOCOL_TYPE_TELNET: path_name = 'telnet' record_path = os.path.join(tp_cfg().core.replay_path, path_name, '{:09d}'.format(int(record_id))) header_file_path = os.path.join(record_path, 'tp-{}.tpr'.format(path_name)) if not os.path.exists(header_file_path): return None, TPE_NOT_EXISTS file = None try: file = open(header_file_path, 'rb') data = file.read() offset = 0 # 读取 `TPPR` 标记(1380995156) 和录像文件版本、录像类型 magic, ver, = struct.unpack_from('=IH', data, offset) offset += 6 if magic != 1380995156: return None, TPE_DATA if ver != 4: # 从v3.5.0开始录像文件版本为版本4 return None, TPE_INCOMPATIBLE_VERSION rec_type, time_used, dat_file_count, = struct.unpack_from( '=HII', data, offset) offset += 10 # TS_RECORD_HEADER_INFO 共计64字节,前面有用的数据读取后,跳过后面补齐用的字节,从第64字节 # 开始解析 TS_RECORD_HEADER_BASIC offset = 64 protocol_type, protocol_sub_type, time_start, width, height = struct.unpack_from( '=HHQHH', data, offset) offset += 16 user_name, = struct.unpack_from('64s', data, offset) user_name = _remove_padding_space(user_name).decode() offset += 64 account, = struct.unpack_from('64s', data, offset) account = _remove_padding_space(account).decode() offset += 64 host_ip, = struct.unpack_from('40s', data, offset) host_ip = _remove_padding_space(host_ip).decode() offset += 40 conn_ip, = struct.unpack_from('40s', data, offset) conn_ip = _remove_padding_space(conn_ip).decode() offset += 40 conn_port, = struct.unpack_from('H', data, offset) offset += 2 client_ip, = struct.unpack_from('40s', data, offset) client_ip = _remove_padding_space(client_ip).decode() offset += 40 except Exception as e: log.e(e) return None, TPE_FAILED finally: if file is not None: file.close() header = dict() header['start'] = time_start # header['pkg_count'] = pkg_count header['time_used'] = time_used header['width'] = width header['height'] = height header['account'] = account header['user_name'] = user_name header['host_ip'] = host_ip header['conn_ip'] = conn_ip header['conn_port'] = conn_port header['client_ip'] = client_ip log.d('header:', header, '\n') return header, TPE_OK
def run(self): log.i('\n') log.i('###############################################################\n') log.i('Load config file: {}\n'.format(self._cfg_file)) log.i('Teleport Web Server starting ...\n') tp_cron().init() # 尝试通过CORE-JSON-RPC获取core服务的配置(主要是ssh/rdp/telnet的端口以及录像文件存放路径) self._get_core_server_config() _db = get_db() if not _db.init(): log.e('can not initialize database interface.\n') return 0 _db.connect() while not _db.connected: log.w('database not connected, retry after 5 seconds.\n') time.sleep(5) _db.connect() cfg = tp_cfg() _db.check_status() if _db.need_create or _db.need_upgrade: cfg.app_mode = APP_MODE_MAINTENANCE tp_cfg().update_sys(None) else: cfg.app_mode = APP_MODE_NORMAL _db.load_system_config() try: # 将运行时配置发送给核心服务 req = {'method': 'set_config', 'param': {'noop_timeout': tp_cfg().sys.session.noop_timeout}} req_data = json.dumps(req) data = urllib.parse.quote(req_data).encode('utf-8') req = urllib.request.Request(url=cfg.common.core_server_rpc, data=data) rep = urllib.request.urlopen(req, timeout=3) body = rep.read().decode() x = json.loads(body) if 'code' not in x or x['code'] != 0: print(x) log.e('connect core-server for set runtime-config failed.\n') else: log.d('set runtime-config for core-server succeeded.\n') except: log.w('can not connect to core-server to set runtime-config, maybe it not start yet, ignore.\n') if not tp_session().init(): log.e('can not initialize session manager.\n') return 0 if not tp_stats().init(): log.e('can not initialize system status collector.\n') return 0 settings = { # 'cookie_secret': '8946svdABGD345fg98uhIaefEBePIfegOIakjFH43oETzK', 'login_url': '/auth/login', # 指定静态文件的路径,页面模板中可以用 {{ static_url('css/main.css') }} 的方式调用 'static_path': cfg.static_path, # 指定模板文件的路径 'template_path': cfg.template_path, # 防止跨站伪造请求,参见 http://old.sebug.net/paper/books/tornado/#_7 'xsrf_cookies': False, 'autoescape': 'xhtml_escape', # 'ui_modules': ui_modules, 'debug': False, # 不开启模板和静态文件的缓存,这样一旦模板文件和静态文件变化,刷新浏览器即可看到更新。 'compiled_template_cache': False, 'static_hash_cache': False, } from app.controller import controllers, fix_controller fix_controller() _app = tornado.web.Application(controllers, **settings) server = tornado.httpserver.HTTPServer(_app, xheaders=True) # server = tornado.httpserver.HTTPServer(_app, ssl_options={ # "certfile": os.path.join(cfg.data_path, 'cert', "server.pem"), # "keyfile": os.path.join(cfg.data_path, 'cert', "server.key"), # }) try: server.listen(cfg.common.port, address=cfg.common.ip) if cfg.common.ip == '0.0.0.0': log.i('works on [http://127.0.0.1:{}]\n'.format(cfg.common.port)) else: log.i('works on [http://{}:{}]\n'.format(cfg.common.ip, cfg.common.port)) except: log.e('can not listen on port {}:{}, make sure it not been used by another application.\n'.format(cfg.common.ip, cfg.common.port)) return 0 # 启动定时任务调度器 tp_cron().start() try: tornado.ioloop.IOLoop.instance().start() except: log.e('\n') tp_cron().stop() return 0