mirror of https://github.com/jumpserver/jumpserver
feat: telnet、ping支持批量测试
parent
904406c5c1
commit
1f2a4b0fb5
|
@ -8,6 +8,7 @@ import struct
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from common.utils import lookup_domain
|
from common.utils import lookup_domain
|
||||||
|
from settings.utils import generate_ips
|
||||||
|
|
||||||
# From /usr/include/linux/icmp.h; your milage may vary.
|
# From /usr/include/linux/icmp.h; your milage may vary.
|
||||||
ICMP_ECHO_REQUEST = 8 # Seems to be the same on Solaris.
|
ICMP_ECHO_REQUEST = 8 # Seems to be the same on Solaris.
|
||||||
|
@ -128,7 +129,7 @@ def ping(dest_addr, timeout, psize, flag=0):
|
||||||
return delay
|
return delay
|
||||||
|
|
||||||
|
|
||||||
async def verbose_ping(dest_ip, timeout=2, count=5, psize=64, display=None):
|
async def verbose_ping(dest_ips, 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.
|
||||||
|
@ -136,34 +137,38 @@ async def verbose_ping(dest_ip, timeout=2, count=5, psize=64, display=None):
|
||||||
if not display:
|
if not display:
|
||||||
return
|
return
|
||||||
|
|
||||||
ip, err = lookup_domain(dest_ip)
|
result = {}
|
||||||
if not ip:
|
ips = generate_ips(dest_ips)
|
||||||
await display(err)
|
await display(f'Total valid address: {len(ips)}\r\n')
|
||||||
return
|
for dest_ip in ips:
|
||||||
|
await display(f'PING {dest_ip}: 56 data bytes')
|
||||||
|
# 切换异步协程
|
||||||
|
await asyncio.sleep(0.1)
|
||||||
|
error_count = 0
|
||||||
|
for i in range(count):
|
||||||
|
try:
|
||||||
|
delay = ping(dest_ip, timeout, psize)
|
||||||
|
except socket.gaierror as e:
|
||||||
|
await display("Failed (socket error: '%s')" % str(e))
|
||||||
|
error_count += 1
|
||||||
|
break
|
||||||
|
|
||||||
await display("PING %s (%s): 56 data bytes" % (dest_ip, ip))
|
if delay is None:
|
||||||
await asyncio.sleep(0.1)
|
await display("Request timeout for icmp_seq %i" % i)
|
||||||
error_count = 0
|
error_count += 1
|
||||||
for i in range(count):
|
else:
|
||||||
try:
|
delay *= 1000
|
||||||
delay = ping(dest_ip, timeout, psize)
|
await display("64 bytes from %s: time=%.3f ms" % (dest_ip, delay))
|
||||||
except socket.gaierror as e:
|
await asyncio.sleep(1)
|
||||||
await display("Failed (socket error: '%s')" % str(e))
|
# 只要有包通过,就认为address是通的
|
||||||
error_count += 1
|
result[dest_ip] = 'failed' if error_count == count else 'ok'
|
||||||
break
|
await display(f'{count} packets transmitted, '
|
||||||
|
f'{count - error_count} packets received, '
|
||||||
|
f'{(error_count / count) * 100}% packet loss\r\n')
|
||||||
|
|
||||||
if delay is None:
|
await display(f'----- Ping statistics -----')
|
||||||
await display("Request timeout for icmp_seq %i" % i)
|
for k, v in result.items():
|
||||||
error_count += 1
|
await display(f'{k}: {v}')
|
||||||
else:
|
|
||||||
delay *= 1000
|
|
||||||
await display("64 bytes from %s: icmp_seq=0 ttl=115 time=%.3f ms" % (ip, delay))
|
|
||||||
await asyncio.sleep(1)
|
|
||||||
|
|
||||||
await display(f'--- {dest_ip} ping statistics ---')
|
|
||||||
await display(f'{count} packets transmitted, '
|
|
||||||
f'{count - error_count} packets received, '
|
|
||||||
f'{(error_count / count) * 100}% packet loss')
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -1,57 +1,53 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import socket
|
||||||
|
import telnetlib
|
||||||
|
|
||||||
from common.utils import lookup_domain
|
from settings.utils import generate_ips
|
||||||
|
|
||||||
PROMPT_REGEX = r'[\<|\[](.*)[\>|\]]'
|
PROMPT_REGEX = r'[\<|\[](.*)[\>|\]]'
|
||||||
|
|
||||||
|
|
||||||
async def telnet(dest_addr, port_number=23, timeout=10):
|
async def telnet(dest_addr, port_number=23, timeout=10):
|
||||||
|
loop = asyncio.get_running_loop()
|
||||||
try:
|
try:
|
||||||
reader, writer = await asyncio.wait_for(
|
connection = await loop.run_in_executor(None, telnetlib.Telnet, dest_addr, port_number, timeout)
|
||||||
asyncio.open_connection(dest_addr, port_number), timeout
|
|
||||||
)
|
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
return False, 'Timeout'
|
return False, 'Timeout'
|
||||||
except (ConnectionRefusedError, OSError) as e:
|
except (ConnectionRefusedError, socket.timeout, socket.gaierror) as e:
|
||||||
return False, str(e)
|
return False, str(e)
|
||||||
try:
|
expected_regexes = [bytes(PROMPT_REGEX, encoding='ascii')]
|
||||||
# 发送命令
|
__, __, output = connection.expect(expected_regexes, timeout=3)
|
||||||
writer.write(b"command\r\n")
|
return True, output.decode('utf-8', 'ignore')
|
||||||
await writer.drain()
|
|
||||||
# 读取响应
|
|
||||||
response = await reader.readuntil()
|
|
||||||
except asyncio.TimeoutError:
|
|
||||||
writer.close()
|
|
||||||
await writer.wait_closed()
|
|
||||||
return False, 'Timeout'
|
|
||||||
writer.close()
|
|
||||||
await writer.wait_closed()
|
|
||||||
return True, response.decode('utf-8', 'ignore')
|
|
||||||
|
|
||||||
|
|
||||||
async def verbose_telnet(dest_ip, dest_port=23, timeout=10, display=None):
|
async def verbose_telnet(dest_ips, dest_port=23, timeout=10, display=None):
|
||||||
if not display:
|
if not display:
|
||||||
return
|
return
|
||||||
|
|
||||||
ip, err = lookup_domain(dest_ip)
|
result = {}
|
||||||
if not ip:
|
ips = generate_ips(dest_ips)
|
||||||
await display(err)
|
await display(f'Total valid address: {len(ips)}\r\n')
|
||||||
return
|
for dest_ip in ips:
|
||||||
|
await display(f'Trying ({dest_ip}:{dest_port})')
|
||||||
|
try:
|
||||||
|
is_connective, resp = await telnet(dest_ip, dest_port, timeout)
|
||||||
|
if is_connective:
|
||||||
|
result[dest_ip] = 'ok'
|
||||||
|
msg = f'Connected to {dest_ip} {dest_port} {resp}.\r\n' \
|
||||||
|
f'Connection closed by foreign host.'
|
||||||
|
else:
|
||||||
|
result[dest_ip] = 'failed'
|
||||||
|
msg = f'Unable to connect to remote host\r\n' \
|
||||||
|
f'Reason: {resp}'
|
||||||
|
except Exception as e:
|
||||||
|
msg = 'Error: %s' % e
|
||||||
|
await display(f'{msg}\r\n')
|
||||||
|
|
||||||
await display(f'Trying {dest_ip} ({ip}:{dest_port})')
|
await display(f'----- Telnet statistics -----')
|
||||||
try:
|
for k, v in result.items():
|
||||||
is_connective, resp = await telnet(dest_ip, dest_port, timeout)
|
await display(f'{k}: {v}')
|
||||||
if is_connective:
|
|
||||||
msg = f'Connected to {dest_ip} {dest_port} {resp}.\r\n' \
|
|
||||||
f'Connection closed by foreign host.'
|
|
||||||
else:
|
|
||||||
msg = f'Unable to connect to remote host\r\n' \
|
|
||||||
f'Reason: {resp}'
|
|
||||||
except Exception as e:
|
|
||||||
msg = 'Error: %s' % e
|
|
||||||
await display(msg)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -3,6 +3,8 @@ from jumpserver.context_processor import default_interface
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from IPy import IP
|
from IPy import IP
|
||||||
|
|
||||||
|
from common.utils import lookup_domain
|
||||||
|
|
||||||
|
|
||||||
def get_interface_setting_or_default():
|
def get_interface_setting_or_default():
|
||||||
if not settings.XPACK_ENABLED:
|
if not settings.XPACK_ENABLED:
|
||||||
|
@ -15,21 +17,23 @@ def get_login_title():
|
||||||
return get_interface_setting_or_default()['login_title']
|
return get_interface_setting_or_default()['login_title']
|
||||||
|
|
||||||
|
|
||||||
def generate_ips(ip_string):
|
def generate_ips(address_string):
|
||||||
# 支持的格式
|
# 支持的格式
|
||||||
# 192.168.1.1,192.168.1.2
|
# 192.168.1.1,192.168.1.2
|
||||||
# 192.168.1.1-12 | 192.168.1.1-192.168.1.12 | 192.168.1.0/30 | 192.168.1.1
|
# 192.168.1.1-12 | 192.168.1.1-192.168.1.12 | 192.168.1.0/30 | 192.168.1.1
|
||||||
ips = []
|
ips = []
|
||||||
ip_list = ip_string.split(',')
|
ip_list = address_string.split(',')
|
||||||
if len(ip_list) > 1:
|
if len(ip_list) > 1:
|
||||||
for ip in ip_list:
|
for ip in ip_list:
|
||||||
try:
|
try:
|
||||||
ips.append(str(IP(ip)))
|
ips.append(str(IP(ip)))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
ip, err = lookup_domain(ip)
|
||||||
|
if not err:
|
||||||
|
ips.append(ip)
|
||||||
return ips
|
return ips
|
||||||
|
|
||||||
ip_list = ip_string.split('-')
|
ip_list = address_string.split('-')
|
||||||
try:
|
try:
|
||||||
if len(ip_list) == 2:
|
if len(ip_list) == 2:
|
||||||
start_ip, end_ip = ip_list
|
start_ip, end_ip = ip_list
|
||||||
|
|
|
@ -22,19 +22,19 @@ class ToolsWebsocket(AsyncJsonWebsocketConsumer):
|
||||||
await self.close()
|
await self.close()
|
||||||
|
|
||||||
async def send_msg(self, msg=''):
|
async def send_msg(self, msg=''):
|
||||||
await self.send_json({'msg': msg + '\r\n'})
|
await self.send_json({'msg': f'{msg}\r\n'})
|
||||||
|
|
||||||
async def imitate_ping(self, dest_ip, timeout=3, count=5, psize=64):
|
async def imitate_ping(self, dest_ips, timeout=3, count=5, psize=64):
|
||||||
params = {
|
params = {
|
||||||
'dest_ip': dest_ip, 'timeout': timeout,
|
'dest_ips': dest_ips, 'timeout': timeout,
|
||||||
'count': count, 'psize': psize
|
'count': count, 'psize': psize
|
||||||
}
|
}
|
||||||
logger.info(f'Receive request ping: {params}')
|
logger.info(f'Receive request ping: {params}')
|
||||||
await verbose_ping(display=self.send_msg, **params)
|
await verbose_ping(display=self.send_msg, **params)
|
||||||
|
|
||||||
async def imitate_telnet(self, dest_ip, dest_port=23, timeout=10):
|
async def imitate_telnet(self, dest_ips, dest_port=23, timeout=10):
|
||||||
params = {
|
params = {
|
||||||
'dest_ip': dest_ip, 'dest_port': dest_port, 'timeout': timeout,
|
'dest_ips': dest_ips, 'dest_port': dest_port, 'timeout': timeout,
|
||||||
}
|
}
|
||||||
logger.info(f'Receive request telnet: {params}')
|
logger.info(f'Receive request telnet: {params}')
|
||||||
await verbose_telnet(display=self.send_msg, **params)
|
await verbose_telnet(display=self.send_msg, **params)
|
||||||
|
|
Loading…
Reference in New Issue