mirror of https://github.com/jumpserver/jumpserver
feat: 系统工具支持traceroute (#11474)
parent
9acb7d6183
commit
da9bd11db5
|
@ -4,3 +4,4 @@ from .ping import *
|
||||||
from .telnet import *
|
from .telnet import *
|
||||||
from .nmap import *
|
from .nmap import *
|
||||||
from .tcpdump import *
|
from .tcpdump import *
|
||||||
|
from .traceroute import *
|
||||||
|
|
|
@ -143,7 +143,7 @@ async def verbose_ping(dest_ips, timeout=2, count=5, psize=64, display=None):
|
||||||
for dest_ip in ips:
|
for dest_ip in ips:
|
||||||
await display(f'PING {dest_ip}: 56 data bytes')
|
await display(f'PING {dest_ip}: 56 data bytes')
|
||||||
# 切换异步协程
|
# 切换异步协程
|
||||||
await asyncio.sleep(0.1)
|
await asyncio.sleep(0.01)
|
||||||
error_count = 0
|
error_count = 0
|
||||||
for i in range(count):
|
for i in range(count):
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
import asyncio
|
||||||
|
import socket
|
||||||
|
import struct
|
||||||
|
import time
|
||||||
|
|
||||||
|
from settings.utils import generate_ips
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_checksum(data):
|
||||||
|
# 计算 ICMP 校验和
|
||||||
|
checksum = 0
|
||||||
|
if len(data) % 2 == 1:
|
||||||
|
data += b'\x00'
|
||||||
|
for i in range(0, len(data), 2):
|
||||||
|
w = (data[i] << 8) + data[i+1]
|
||||||
|
checksum += w
|
||||||
|
checksum = (checksum >> 16) + (checksum & 0xffff)
|
||||||
|
checksum = ~checksum & 0xffff
|
||||||
|
return checksum
|
||||||
|
|
||||||
|
|
||||||
|
async def once_traceroute(target, display, max_hops=30, timeout=3):
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
icmp = socket.getprotobyname('icmp')
|
||||||
|
sock_fd = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp)
|
||||||
|
for ttl in range(1, max_hops+1):
|
||||||
|
# 设置 TTL
|
||||||
|
sock_fd.setsockopt(socket.IPPROTO_IP, socket.IP_TTL, ttl)
|
||||||
|
# 设置超时时间
|
||||||
|
sock_fd.settimeout(timeout)
|
||||||
|
# 发送 ICMP Echo 请求数据包
|
||||||
|
packet = struct.pack('!BBHHH', 8, 0, 0, 12345, ttl)
|
||||||
|
checksum = calculate_checksum(packet)
|
||||||
|
packet = struct.pack('!BBHHH', 8, 0, checksum, 12345, ttl)
|
||||||
|
start_time = time.time()
|
||||||
|
sock_fd.sendto(packet, (target, 0))
|
||||||
|
await asyncio.sleep(0.01)
|
||||||
|
try:
|
||||||
|
# 接收 ICMP Echo Reply 数据包
|
||||||
|
recv_packet, addr = await loop.sock_recvfrom(sock_fd, 1024)
|
||||||
|
end_time = time.time()
|
||||||
|
# 解析目标地址
|
||||||
|
dest_ip = addr[0]
|
||||||
|
# 获取跃点信息
|
||||||
|
hop_info = f'{ttl} {dest_ip} ({dest_ip})'
|
||||||
|
# 获取延迟时间信息
|
||||||
|
delay_info = f'{(end_time - start_time) * 1000:.3f} ms'
|
||||||
|
# 打印跃点信息和延迟时间
|
||||||
|
await display(f'{hop_info:<4} {delay_info}')
|
||||||
|
if dest_ip == target:
|
||||||
|
return
|
||||||
|
except socket.timeout:
|
||||||
|
# 发生超时,跳出循环
|
||||||
|
await display(f'{ttl} *')
|
||||||
|
sock_fd.close()
|
||||||
|
|
||||||
|
|
||||||
|
async def verbose_traceroute(dest_ips, timeout=10, display=None):
|
||||||
|
if not display:
|
||||||
|
return
|
||||||
|
|
||||||
|
ips = generate_ips(dest_ips)
|
||||||
|
await display(f'Total valid address: {len(ips)}\r\n')
|
||||||
|
for dest_ip in ips:
|
||||||
|
await display(f'traceroute to {dest_ip}, 30 hops max, 60 byte packets')
|
||||||
|
msg = ''
|
||||||
|
try:
|
||||||
|
await once_traceroute(dest_ip, display)
|
||||||
|
except Exception as e:
|
||||||
|
msg = f'Error: {e}'
|
||||||
|
await display(msg)
|
|
@ -18,19 +18,21 @@ def get_login_title():
|
||||||
|
|
||||||
|
|
||||||
def generate_ips(address_string):
|
def generate_ips(address_string):
|
||||||
|
def transform(_ip):
|
||||||
|
real_ip, err_msg = lookup_domain(_ip)
|
||||||
|
return _ip if err_msg else real_ip
|
||||||
# 支持的格式
|
# 支持的格式
|
||||||
# 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 = address_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(transform(ip))))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
ip, err = lookup_domain(ip)
|
pass
|
||||||
if not err:
|
if ips:
|
||||||
ips.append(ip)
|
|
||||||
return ips
|
return ips
|
||||||
|
|
||||||
ip_list = address_string.split('-')
|
ip_list = address_string.split('-')
|
||||||
|
@ -58,6 +60,7 @@ def is_valid_port(port):
|
||||||
valid = False
|
valid = False
|
||||||
return valid
|
return valid
|
||||||
|
|
||||||
|
|
||||||
def generate_ports(ports):
|
def generate_ports(ports):
|
||||||
port_list = []
|
port_list = []
|
||||||
if isinstance(ports, int):
|
if isinstance(ports, int):
|
||||||
|
|
|
@ -6,7 +6,10 @@ from channels.generic.websocket import AsyncJsonWebsocketConsumer
|
||||||
|
|
||||||
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 .tools import verbose_ping, verbose_telnet, verbose_nmap, verbose_tcpdump
|
from .tools import (
|
||||||
|
verbose_ping, verbose_telnet, verbose_nmap,
|
||||||
|
verbose_tcpdump, verbose_traceroute
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
@ -57,6 +60,10 @@ class ToolsWebsocket(AsyncJsonWebsocketConsumer):
|
||||||
logger.info(f'Receive request tcpdump: {params}')
|
logger.info(f'Receive request tcpdump: {params}')
|
||||||
await verbose_tcpdump(display=self.send_msg, **params)
|
await verbose_tcpdump(display=self.send_msg, **params)
|
||||||
|
|
||||||
|
async def imitate_traceroute(self,dest_ips):
|
||||||
|
params = {'dest_ips': dest_ips}
|
||||||
|
await verbose_traceroute(display=self.send_msg, **params)
|
||||||
|
|
||||||
async def receive(self, text_data=None, bytes_data=None, **kwargs):
|
async def receive(self, text_data=None, bytes_data=None, **kwargs):
|
||||||
data = json.loads(text_data)
|
data = json.loads(text_data)
|
||||||
tool_type = data.pop('tool_type', 'Ping')
|
tool_type = data.pop('tool_type', 'Ping')
|
||||||
|
|
Loading…
Reference in New Issue