160 lines
5.8 KiB
Python
160 lines
5.8 KiB
Python
|
|
import json
|
|||
|
|
import os
|
|||
|
|
import sys
|
|||
|
|
from datetime import datetime
|
|||
|
|
|
|||
|
|
if "/www/server/panel/class" not in sys.path:
|
|||
|
|
sys.path.insert(0, "/www/server/panel/class")
|
|||
|
|
|
|||
|
|
os.chdir("/www/server/panel")
|
|||
|
|
import public
|
|||
|
|
|
|||
|
|
|
|||
|
|
class SSHbase:
|
|||
|
|
def __init__(self):
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def return_area(result, key):
|
|||
|
|
"""
|
|||
|
|
@name 格式化返回带IP归属地的数组
|
|||
|
|
@param result<list> 数据数组
|
|||
|
|
@param key<str> ip所在字段
|
|||
|
|
@return list
|
|||
|
|
"""
|
|||
|
|
if not result:
|
|||
|
|
return result
|
|||
|
|
|
|||
|
|
# 添加IP查询缓存
|
|||
|
|
ip_cache_file = 'data/ip_location_cache.json'
|
|||
|
|
ip_cache = {}
|
|||
|
|
|
|||
|
|
# 确保缓存目录存在
|
|||
|
|
cache_dir = os.path.dirname(ip_cache_file)
|
|||
|
|
if not os.path.exists(cache_dir):
|
|||
|
|
os.makedirs(cache_dir, exist_ok=True)
|
|||
|
|
|
|||
|
|
# 读取IP缓存
|
|||
|
|
try:
|
|||
|
|
if os.path.exists(ip_cache_file):
|
|||
|
|
ip_cache = json.loads(public.readFile(ip_cache_file))
|
|||
|
|
except Exception as e:
|
|||
|
|
public.print_log('Failed to read IP cache: {}'.format(str(e)))
|
|||
|
|
ip_cache = {}
|
|||
|
|
|
|||
|
|
# 只查询未缓存的IP
|
|||
|
|
new_ips = set()
|
|||
|
|
for data in result:
|
|||
|
|
ip = data.get(key)
|
|||
|
|
if not ip or public.is_ipv6(ip):
|
|||
|
|
continue
|
|||
|
|
if ip not in ip_cache:
|
|||
|
|
new_ips.add(ip)
|
|||
|
|
|
|||
|
|
# 批量查询新IP
|
|||
|
|
for ip in new_ips:
|
|||
|
|
try:
|
|||
|
|
if "127.0.0" in ip:
|
|||
|
|
ip_cache[ip] = {"info": "Local address (e.g. left terminal)"}
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
ip_area = public.get_ip_location(ip)
|
|||
|
|
if not ip_area:
|
|||
|
|
ip_cache[ip] = {"info": "unknown area"}
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
ip_area = ip_area.raw
|
|||
|
|
country = ip_area.get("country", {})
|
|||
|
|
ip_area["info"] = "{} {} {}".format(
|
|||
|
|
country.get('country', 'unknown'),
|
|||
|
|
country.get('province', 'unknown'),
|
|||
|
|
country.get('city', 'unknown')
|
|||
|
|
) if country else "unknown area"
|
|||
|
|
ip_cache[ip] = ip_area
|
|||
|
|
except Exception as e:
|
|||
|
|
public.print_log('Query IP {} Failed: {}'.format(ip, str(e)))
|
|||
|
|
ip_cache[ip] = {"info": "unknown area"}
|
|||
|
|
|
|||
|
|
# 只有当有新IP被查询时才更新缓存文件
|
|||
|
|
if new_ips:
|
|||
|
|
try:
|
|||
|
|
public.writeFile(ip_cache_file, json.dumps(ip_cache))
|
|||
|
|
except Exception as e:
|
|||
|
|
public.print_log('Failed to update IP cache: {}'.format(str(e)))
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
# 使用缓存数据,确保不修改原始数据
|
|||
|
|
result_with_area = []
|
|||
|
|
for data in result:
|
|||
|
|
data_copy = data.copy() # 创建数据副本
|
|||
|
|
ip = data_copy.get(key, '')
|
|||
|
|
data_copy['area'] = ip_cache.get(ip, {"info": "unknown area"})
|
|||
|
|
result_with_area.append(data_copy)
|
|||
|
|
|
|||
|
|
return result_with_area
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def journalctl_system():
|
|||
|
|
try:
|
|||
|
|
if os.path.exists('/etc/os-release'):
|
|||
|
|
f = public.readFile('/etc/os-release')
|
|||
|
|
f = f.split('\n')
|
|||
|
|
ID = ''
|
|||
|
|
VERSION_ID = 0
|
|||
|
|
for line in f:
|
|||
|
|
if line.startswith('VERSION_ID'):
|
|||
|
|
VERSION_ID = int(line.split('=')[1].split('.')[0].strip('"'))
|
|||
|
|
if line.startswith('ID'):
|
|||
|
|
if ID != '': continue
|
|||
|
|
ID = line.strip().split('=')[1].strip('"')
|
|||
|
|
try:
|
|||
|
|
ID = ID.split('.')[0]
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
if (ID.lower() == 'debian' and VERSION_ID >= 11) or (ID.lower() == 'ubuntu' and VERSION_ID >= 20):
|
|||
|
|
return True
|
|||
|
|
return False
|
|||
|
|
except:
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def parse_login_entry(parts, year):
|
|||
|
|
"""解析登录条目"""
|
|||
|
|
try:
|
|||
|
|
# 判断日志格式类型
|
|||
|
|
if 'T' in parts[0]: # centos7以外的格式
|
|||
|
|
# 解析ISO格式时间戳
|
|||
|
|
dt = datetime.fromisoformat(parts[0].replace('Z', '+00:00'))
|
|||
|
|
user_index = parts.index('user') + 1 if 'user' in parts else parts.index('for') + 1
|
|||
|
|
ip_index = parts.index('from') + 1
|
|||
|
|
port_index = parts.index('port') + 1 if 'port' in parts else -1
|
|||
|
|
else:
|
|||
|
|
# 解析传统格式时间
|
|||
|
|
month = parts[0]
|
|||
|
|
day = parts[1]
|
|||
|
|
time_str = parts[2]
|
|||
|
|
# 如果月份大于当前月,说明年份不对,直接把year修改成1970年
|
|||
|
|
if datetime.strptime("{} {}".format(month, day), "%b %d").month > datetime.now().month:
|
|||
|
|
year = "1970"
|
|||
|
|
dt_str = "{} {} {} {}".format(month, day, year, time_str)
|
|||
|
|
dt = datetime.strptime(dt_str, "%b %d %Y %H:%M:%S")
|
|||
|
|
user_index = parts.index('for') + 1 if "invalid" not in parts else -6
|
|||
|
|
ip_index = parts.index('from') + 1
|
|||
|
|
port_index = parts.index('port') + 1 if 'port' in parts else -1
|
|||
|
|
|
|||
|
|
entry = {
|
|||
|
|
"timestamp": int(dt.timestamp()),
|
|||
|
|
"time": dt.strftime("%Y-%m-%d %H:%M:%S"),
|
|||
|
|
"type": "success" if ("Accepted" in parts) else "failed",
|
|||
|
|
"status": 1 if ("Accepted" in parts) else 0,
|
|||
|
|
"user": parts[user_index],
|
|||
|
|
"address": parts[ip_index],
|
|||
|
|
"port": parts[port_index] if port_index != -1 else "",
|
|||
|
|
"deny_status": 0,
|
|||
|
|
"login_type": "publickey" if "publickey" in parts else "password" # 添加登录类型
|
|||
|
|
}
|
|||
|
|
return entry
|
|||
|
|
except Exception as e:
|
|||
|
|
public.print_log(public.get_error_info())
|
|||
|
|
return None
|