mirror of https://github.com/jumpserver/jumpserver
feat: 系统工具增加服务器时间及nmap工具 (#11078)
parent
1239ffd4c8
commit
1907c795c3
|
@ -4,13 +4,14 @@ from rest_framework.permissions import AllowAny
|
||||||
|
|
||||||
from common.permissions import IsValidUserOrConnectionToken
|
from common.permissions import IsValidUserOrConnectionToken
|
||||||
from common.utils import get_logger, lazyproperty
|
from common.utils import get_logger, lazyproperty
|
||||||
|
from common.utils.timezone import local_now
|
||||||
from jumpserver.utils import has_valid_xpack_license, get_xpack_license_info
|
from jumpserver.utils import has_valid_xpack_license, get_xpack_license_info
|
||||||
from .. import serializers
|
from .. import serializers
|
||||||
from ..utils import get_interface_setting_or_default
|
from ..utils import get_interface_setting_or_default
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
__all__ = ['PublicSettingApi', 'OpenPublicSettingApi']
|
__all__ = ['PublicSettingApi', 'OpenPublicSettingApi', 'ServerInfoApi']
|
||||||
|
|
||||||
|
|
||||||
class OpenPublicSettingApi(generics.RetrieveAPIView):
|
class OpenPublicSettingApi(generics.RetrieveAPIView):
|
||||||
|
@ -55,3 +56,13 @@ class PublicSettingApi(OpenPublicSettingApi):
|
||||||
# 提前把异常爆出来
|
# 提前把异常爆出来
|
||||||
values[name] = getattr(settings, name)
|
values[name] = getattr(settings, name)
|
||||||
return values
|
return values
|
||||||
|
|
||||||
|
|
||||||
|
class ServerInfoApi(generics.RetrieveAPIView):
|
||||||
|
permission_classes = (IsValidUserOrConnectionToken,)
|
||||||
|
serializer_class = serializers.ServerInfoSerializer
|
||||||
|
|
||||||
|
def get_object(self):
|
||||||
|
return {
|
||||||
|
"CURRENT_TIME": local_now(),
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
__all__ = ['PublicSettingSerializer', 'PrivateSettingSerializer']
|
__all__ = [
|
||||||
|
'PublicSettingSerializer', 'PrivateSettingSerializer', 'ServerInfoSerializer'
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class PublicSettingSerializer(serializers.Serializer):
|
class PublicSettingSerializer(serializers.Serializer):
|
||||||
|
@ -50,3 +52,7 @@ class PrivateSettingSerializer(PublicSettingSerializer):
|
||||||
|
|
||||||
TICKETS_ENABLED = serializers.BooleanField()
|
TICKETS_ENABLED = serializers.BooleanField()
|
||||||
CONNECTION_TOKEN_REUSABLE = serializers.BooleanField()
|
CONNECTION_TOKEN_REUSABLE = serializers.BooleanField()
|
||||||
|
|
||||||
|
|
||||||
|
class ServerInfoSerializer(serializers.Serializer):
|
||||||
|
CURRENT_TIME = serializers.DateTimeField()
|
||||||
|
|
|
@ -23,4 +23,5 @@ urlpatterns = [
|
||||||
path('logo/', api.SettingsLogoApi.as_view(), name='settings-logo'),
|
path('logo/', api.SettingsLogoApi.as_view(), name='settings-logo'),
|
||||||
path('public/', api.PublicSettingApi.as_view(), name='public-setting'),
|
path('public/', api.PublicSettingApi.as_view(), name='public-setting'),
|
||||||
path('public/open/', api.OpenPublicSettingApi.as_view(), name='open-public-setting'),
|
path('public/open/', api.OpenPublicSettingApi.as_view(), name='open-public-setting'),
|
||||||
|
path('server-info/', api.ServerInfoApi.as_view(), name='server-info'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -5,3 +5,4 @@ from .ldap import *
|
||||||
from .common import *
|
from .common import *
|
||||||
from .ping import *
|
from .ping import *
|
||||||
from .telnet import *
|
from .telnet import *
|
||||||
|
from .nmap import *
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
import time
|
||||||
|
import nmap
|
||||||
|
|
||||||
|
from IPy import IP
|
||||||
|
|
||||||
|
from common.utils.timezone import local_now_display
|
||||||
|
|
||||||
|
|
||||||
|
def generate_ips(ip_string):
|
||||||
|
# 支持的格式
|
||||||
|
# 192.168.1.1-12 | 192.168.1.1-192.168.1.12 | 192.168.1.0/30 | 192.168.1.1
|
||||||
|
ip_list = ip_string.split('-')
|
||||||
|
ips = []
|
||||||
|
try:
|
||||||
|
if len(ip_list) == 2:
|
||||||
|
start_ip, end_ip = ip_list
|
||||||
|
if ip_list[1].find('.') == -1:
|
||||||
|
end_ip = start_ip[:start_ip.rindex('.') + 1] + end_ip
|
||||||
|
for ip in range(IP(start_ip).int(), IP(end_ip).int() + 1):
|
||||||
|
ips.extend(IP(ip))
|
||||||
|
else:
|
||||||
|
ips.extend(IP(ip_list[0]))
|
||||||
|
except Exception:
|
||||||
|
ips = []
|
||||||
|
return ips
|
||||||
|
|
||||||
|
|
||||||
|
def once_nmap(nm, ip, ports, timeout, display):
|
||||||
|
nmap_version = '.'.join(map(lambda x: str(x), nm.nmap_version()))
|
||||||
|
display(f'Starting Nmap {nmap_version} at {local_now_display()} for {ip}')
|
||||||
|
try:
|
||||||
|
is_ok = True
|
||||||
|
nm.scan(ip, arguments='-sS -sU -F', ports=ports, timeout=timeout)
|
||||||
|
tcp_port = nm[ip].get('tcp', {})
|
||||||
|
udp_port = nm[ip].get('udp', {})
|
||||||
|
display(f'PORT\tSTATE\tSERVICE')
|
||||||
|
for port, info in tcp_port.items():
|
||||||
|
display(f"{port}\t{info.get('state', 'unknown')}\t{info.get('name', 'unknown')}")
|
||||||
|
for port, info in udp_port.items():
|
||||||
|
display(f"{port}\t{info.get('state', 'unknown')}\t{info.get('name', 'unknown')}")
|
||||||
|
except Exception:
|
||||||
|
is_ok = False
|
||||||
|
display(f'Nmap scan report for {ip} error.')
|
||||||
|
return is_ok
|
||||||
|
|
||||||
|
|
||||||
|
def verbose_nmap(dest_ip, dest_port=None, timeout=None, display=print):
|
||||||
|
dest_port = ','.join(list(dest_port)) if dest_port else None
|
||||||
|
|
||||||
|
ips = generate_ips(dest_ip)
|
||||||
|
nm = nmap.PortScanner()
|
||||||
|
success_num, start_time = 0, time.time()
|
||||||
|
display(f'[Summary] Nmap: {len(ips)} IP addresses were scanned')
|
||||||
|
for ip in ips:
|
||||||
|
ok = once_nmap(nm, str(ip), dest_port, timeout, display)
|
||||||
|
if ok:
|
||||||
|
success_num += 1
|
||||||
|
display('')
|
||||||
|
display(f'[Done] Nmap: {len(ips)} IP addresses ({success_num} hosts up) '
|
||||||
|
f'scanned in {round(time.time() - start_time, 2)} seconds')
|
|
@ -128,30 +128,37 @@ def ping(dest_addr, timeout, psize, flag=0):
|
||||||
return delay
|
return delay
|
||||||
|
|
||||||
|
|
||||||
def verbose_ping(dest_addr, timeout=2, count=5, psize=64, display=None):
|
def verbose_ping(dest_ip, timeout=2, count=5, psize=64, display=None):
|
||||||
"""
|
"""
|
||||||
Send `count' ping with `psize' size to `dest_addr' with
|
Send `count' ping with `psize' size to `dest_addr' with
|
||||||
the given `timeout' and display the result.
|
the given `timeout' and display the result.
|
||||||
"""
|
"""
|
||||||
ip = lookup_domain(dest_addr)
|
ip = lookup_domain(dest_ip)
|
||||||
if not ip:
|
if not ip:
|
||||||
return
|
return
|
||||||
if display is None:
|
if display is None:
|
||||||
display = print
|
display = print
|
||||||
display("PING %s (%s): 56 data bytes" % (dest_addr, ip))
|
error_count = 0
|
||||||
|
display("PING %s (%s): 56 data bytes" % (dest_ip, ip))
|
||||||
for i in range(count):
|
for i in range(count):
|
||||||
try:
|
try:
|
||||||
delay = ping(dest_addr, timeout, psize)
|
delay = ping(dest_ip, timeout, psize)
|
||||||
except socket.gaierror as e:
|
except socket.gaierror as e:
|
||||||
display("failed. (socket error: '%s')" % str(e))
|
display("failed. (socket error: '%s')" % str(e))
|
||||||
|
error_count += 1
|
||||||
break
|
break
|
||||||
|
|
||||||
if delay is None:
|
if delay is None:
|
||||||
display("Request timeout for icmp_seq %i" % i)
|
display("Request timeout for icmp_seq %i" % i)
|
||||||
|
error_count += 1
|
||||||
else:
|
else:
|
||||||
delay = delay * 1000
|
delay *= 1000
|
||||||
display("64 bytes from %s: icmp_seq=0 ttl=115 time=%.3f ms" % (ip, delay))
|
display("64 bytes from %s: icmp_seq=0 ttl=115 time=%.3f ms" % (ip, delay))
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
display(f'--- {dest_ip} ping statistics ---')
|
||||||
|
display(f'{count} packets transmitted, '
|
||||||
|
f'{count - error_count} packets received, '
|
||||||
|
f'{(error_count / count) * 100}% packet loss')
|
||||||
print()
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,21 +18,21 @@ def telnet(dest_addr, port_number=23, timeout=10):
|
||||||
return True, output.decode('utf-8', 'ignore')
|
return True, output.decode('utf-8', 'ignore')
|
||||||
|
|
||||||
|
|
||||||
def verbose_telnet(dest_addr, port_number=23, timeout=10, display=None):
|
def verbose_telnet(dest_ip, dest_port=23, timeout=10, display=None):
|
||||||
if display is None:
|
if display is None:
|
||||||
display = print
|
display = print
|
||||||
ip = lookup_domain(dest_addr)
|
ip = lookup_domain(dest_ip)
|
||||||
if not ip:
|
if not ip:
|
||||||
return
|
return
|
||||||
msg = 'Trying %s (%s:%s)' % (dest_addr, ip, port_number)
|
msg = 'Trying %s (%s:%s)' % (dest_ip, ip, dest_port)
|
||||||
display(msg)
|
display(msg)
|
||||||
try:
|
try:
|
||||||
is_connective, resp = telnet(dest_addr, port_number, timeout)
|
is_connective, resp = telnet(dest_ip, dest_port, timeout)
|
||||||
if is_connective:
|
if is_connective:
|
||||||
template = 'Connected to {0} {1}.\r\n{2}Connection closed by foreign host.'
|
template = 'Connected to {0} {1}.\r\n{2}Connection closed by foreign host.'
|
||||||
else:
|
else:
|
||||||
template = 'telnet: connect to {0} {1} {2}\r\ntelnet: Unable to connect to remote host'
|
template = 'telnet: connect to {0} {1} {2}\r\ntelnet: Unable to connect to remote host'
|
||||||
msg = template.format(dest_addr, port_number, resp)
|
msg = template.format(dest_ip, dest_port, resp)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
msg = 'Error: %s' % e
|
msg = 'Error: %s' % e
|
||||||
display(msg)
|
display(msg)
|
||||||
|
|
|
@ -7,7 +7,7 @@ from channels.generic.websocket import JsonWebsocketConsumer
|
||||||
|
|
||||||
from common.db.utils import close_old_connections
|
from common.db.utils import close_old_connections
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
from .utils import verbose_ping, verbose_telnet
|
from .utils import verbose_ping, verbose_telnet, verbose_nmap
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
@ -24,27 +24,28 @@ class ToolsWebsocket(JsonWebsocketConsumer):
|
||||||
def send_msg(self, msg):
|
def send_msg(self, msg):
|
||||||
self.send_json({'msg': msg + '\r\n'})
|
self.send_json({'msg': msg + '\r\n'})
|
||||||
|
|
||||||
def imitate_ping(self, dest_addr, timeout=3, count=5, psize=64):
|
def imitate_ping(self, dest_ip, timeout=3, count=5, psize=64):
|
||||||
"""
|
"""
|
||||||
Send `count' ping with `psize' size to `dest_addr' with
|
Send `count' ping with `psize' size to `dest_ip' with
|
||||||
the given `timeout' and display the result.
|
the given `timeout' and display the result.
|
||||||
"""
|
"""
|
||||||
logger.info('receive request ping {}'.format(dest_addr))
|
logger.info('receive request ping {}'.format(dest_ip))
|
||||||
verbose_ping(dest_addr, timeout, count, psize, display=self.send_msg)
|
verbose_ping(dest_ip, timeout, count, psize, display=self.send_msg)
|
||||||
|
|
||||||
def imitate_telnet(self, dest_addr, port_num=23, timeout=10):
|
def imitate_telnet(self, dest_ip, dest_port=23, timeout=10):
|
||||||
logger.info('receive request telnet {}'.format(dest_addr))
|
logger.info('receive request telnet {}'.format(dest_ip))
|
||||||
verbose_telnet(dest_addr, port_num, timeout, display=self.send_msg)
|
verbose_telnet(dest_ip, dest_port, timeout, display=self.send_msg)
|
||||||
|
|
||||||
|
def imitate_nmap(self, dest_ip, dest_port=None, timeout=None):
|
||||||
|
logger.info('receive request nmap {}'.format(dest_ip))
|
||||||
|
verbose_nmap(dest_ip, dest_port, timeout, display=self.send_msg)
|
||||||
|
|
||||||
def receive(self, text_data=None, bytes_data=None, **kwargs):
|
def receive(self, text_data=None, bytes_data=None, **kwargs):
|
||||||
data = json.loads(text_data)
|
data = json.loads(text_data)
|
||||||
tool_type = data.get('tool_type', 'Ping')
|
tool_type = data.pop('tool_type', 'Ping')
|
||||||
dest_addr = data.get('dest_addr')
|
|
||||||
if tool_type == 'Ping':
|
tool_func = getattr(self, f'imitate_{tool_type.lower()}')
|
||||||
self.imitate_ping(dest_addr)
|
tool_func(**data)
|
||||||
else:
|
|
||||||
port_num = data.get('port_num')
|
|
||||||
self.imitate_telnet(dest_addr, port_num)
|
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
def disconnect(self, code):
|
def disconnect(self, code):
|
||||||
|
|
Loading…
Reference in New Issue