diff --git a/apps/cmdb/urls.py b/apps/cmdb/urls.py index 2e2503c..c64f485 100644 --- a/apps/cmdb/urls.py +++ b/apps/cmdb/urls.py @@ -1,7 +1,7 @@ from django.urls import path from .views import CmdbView -from . import views_code +from . import views_code, views_scan app_name = 'cmdb' @@ -12,4 +12,6 @@ urlpatterns = [ path('portal/code/list/', views_code.CodeListView.as_view(), name='portal-code-list'), path('portal/code/update/', views_code.CodeUpdateView.as_view(), name='portal-code-update'), path('portal/code/delete/', views_code.CodeDeleteView.as_view(), name='portal-code-delete'), + + path('portal/scan_config/', views_scan.ScanConfigView.as_view(), name='portal-scan_config'), ] diff --git a/apps/cmdb/views_scan.py b/apps/cmdb/views_scan.py new file mode 100644 index 0000000..bffd7c5 --- /dev/null +++ b/apps/cmdb/views_scan.py @@ -0,0 +1,54 @@ +# @Time : 2018/12/29 19:25 +# @Author : RobbieHan +# @File : views_scan.py + +import ast +import logging +from ruamel import yaml + +from django.views.generic import View +from django.http import JsonResponse +from django.shortcuts import render + + +from system.mixin import LoginRequiredMixin +from custom import BreadcrumbMixin +from utils.sandbox_utils import ConfigFileMixin +from system.models import Menu + +error_logger = logging.getLogger('sandbox_error') + + +class ScanConfigView(LoginRequiredMixin, BreadcrumbMixin, ConfigFileMixin, View): + + def get(self, request): + menu = Menu.get_menu_by_request_url(request.path_info) + template_name = 'cmdb/scan_config.html' + context = self.get_conf_content() + context.update(menu) + return render(request, template_name, context) + + def post(self, request): + ret = dict(result=False) + config = dict() + hosts = request.POST + try: + config['net_address'] = ast.literal_eval(hosts['net_address']) + config['ssh_username'] = hosts['ssh_username'] + config['ssh_port'] = hosts['ssh_port'] + config['ssh_password'] = hosts['ssh_password'] + config['ssh_private_key'] = hosts['ssh_private_key'] + config['commands'] = ast.literal_eval(hosts['commands']) + config['auth_type'] = hosts['auth_type'] + config['scan_type'] = hosts['scan_type'] + config['email'] = hosts['email'] + config['send_email'] = hosts['send_email'] + data = dict(hosts=config) + config_file = self.get_config_file() + with open(config_file, 'w', encoding='utf-8') as f: + yaml.dump(data, f, Dumper=yaml.RoundTripDumper, indent=4) + ret['result'] = True + except Exception as e: + error_logger.error(e) + + return JsonResponse(ret) diff --git a/apps/utils/__init__.py b/apps/utils/__init__.py new file mode 100644 index 0000000..1caca67 --- /dev/null +++ b/apps/utils/__init__.py @@ -0,0 +1,3 @@ +# @Time : 2018/12/29 16:26 +# @Author : RobbieHan +# @File : __init__.py.py \ No newline at end of file diff --git a/apps/utils/sandbox_utils.py b/apps/utils/sandbox_utils.py new file mode 100644 index 0000000..44c3e4b --- /dev/null +++ b/apps/utils/sandbox_utils.py @@ -0,0 +1,74 @@ +# @Time : 2018/12/29 19:22 +# @Author : RobbieHan +# @File : sandbox_utils.py + +import os + +from django.conf import settings + +import yaml +import logging + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sandboxMP.settings') +error_logger = logging.getLogger('sandbox_error') + + +class ConfigFileMixin: + config_file = None + + def get_config_file(self): + """ + Return 'config_file' that will be used to look up the scan hosts IP, + network, range of IP, or other config settings. + This method is called by the default implementation of get_hosts(), + """ + + if self.config_file is None: + config_file = os.path.join(os.path.join(settings.BASE_DIR, 'config'), 'scanhosts.yml') + if os.path.exists(config_file): + return config_file + else: + msg = ' %(cls)s is missing a config file. Define %(cls)s.config_file, ' \ + 'or override %(cls)s.get_config_file().' % {'cls': self.__class__.__name__} + error_logger.error(msg) + raise ValueError(msg) + + return self.config_file + + def get_conf_content(self, *key): + """ + Get the configuration content from config file . + Example ssh_password, commands, email which is in the config file. + """ + _config = self.get_config_file() + with open(_config) as f: + content = yaml.load(f) + if key is not None: + try: + num = 0 + while num < len(key): + content = content[key[num]] + num += 1 + except Exception as e: + msg = '%(exc)s is not in %(config)s.' % { + 'exc': e, + 'config': _config + } + error_logger.error(msg) + raise ValueError(msg) + return content + + def get_commands(self): + """ + Get the commands from config file. + """ + key = ['hosts', 'commands'] + return self.get_conf_content(*key) + + def get_net_address(self): + """ + Return the hosts that will be used to scan. + Subclasses can override this to return any hosts. + """ + key = ['hosts', 'net_address'] + return self.get_conf_content(*key) diff --git a/config/scanhosts.yml b/config/scanhosts.yml new file mode 100644 index 0000000..10d2bd8 --- /dev/null +++ b/config/scanhosts.yml @@ -0,0 +1,18 @@ +hosts: + net_address: + - '172.16.3.0/24' + - '172.16.2.100-105' + ssh_username: 'root' + ssh_port: '22' + ssh_password: '1234@abcd.com' + ssh_private_key: '/root/.ssh/id_rsa' + commands: + sys_hostname: 'hostname' + mac_address: 'cat /sys/class/net/[^tsbvl]*/address' + sn_number: 'dmidecode -s system-serial-number' + os_type: 'cat /etc/redhat-release' + device_type: 'echo `dmidecode -s system-manufacturer && dmidecode -s system-product-name`' + email: 'robbie_han@outlook.com' + send_email: 'false' + scan_type: 'basic_scan' + auth_type: 'private_key' diff --git a/templates/cmdb/scan_config.html b/templates/cmdb/scan_config.html new file mode 100644 index 0000000..e833fab --- /dev/null +++ b/templates/cmdb/scan_config.html @@ -0,0 +1,176 @@ +{% extends "base-left.html" %} +{% load staticfiles %} + +{% block css %} + +{% endblock %} + +{% block content %} + + +
+
+
+ +
+
+

扫面参数配置

+
+ + +
+ {% csrf_token %} +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+
+ + +
+ +
+ +
+
+ +
+ + +
+
+
+ + + +
+
+
+
+
+
+

参数配置说明

+
+
+ 扫描网段必填参数 +

网络扫描地址列表,列表中可以包含一个或多个网段,也可以是一个或多个地址区间,例如['192.168.100.0/24', '192.168.100.10-20']

+ 登陆用户必填参数 +

系统登陆测试使用的用户名,默认root。

+ 登陆密码可选参数 +

系统登陆测试使用的密码,如过认证方式为密码认证,必须填写密码信息。

+ 密钥路径可选参数 +

系统登陆测试使用的密钥存放路径,如过认证方式为私钥认证,必须填写密钥路径。

+ 运行命令预定义参数 +

登陆系统后运行的基本命令,用来获取系统基本信息,当扫描方式为加强扫描时,才会执行运行命令,运行命令为预定义,禁止修改。

+ 认证方式可选参数 +

系统登陆认证方式,包括密码认证和私钥认证两种方式,当扫描方式为加强扫描时,需要设定认证方式。

+ 扫描方式可选参数 +

系统扫描方式,包括基本扫描和加强扫描,当设置为加强扫描时会登陆系统执行运行命令获取系统信息。

+ 收件邮箱可选参数 +

用于接收扫描结果邮件,可以通过发送邮件选项设置是否发送通知邮件。

+
+
+
+ +
+
+ + + +{% endblock %} + +{% block javascripts %} + + +{% endblock %} \ No newline at end of file