show url requests

This commit is contained in:
Thomas Ciesla
2026-01-09 15:11:30 +01:00
parent 13fd0daf6d
commit a435ba5c8c
2 changed files with 71 additions and 11 deletions

View File

@@ -1331,6 +1331,10 @@ class LiveStatsTracker:
self.blocked_paths: Dict[str, List[float]] = {} # Path -> [blocked timestamps]
self.ip_404s: Dict[str, List[float]] = {} # IP -> [404 timestamps]
# IP Request Details (für IP-Detail Popup)
self.ip_request_details: Dict[str, List[Dict]] = {} # IP -> [{ts, path, ua}, ...]
self.max_request_details = 100 # Max Anzahl Details pro IP
# Human/Bot Counters
self.human_requests: List[float] = []
self.bot_requests: List[float] = []
@@ -1353,7 +1357,13 @@ class LiveStatsTracker:
self.human_requests = [t for t in self.human_requests if t > cutoff]
self.bot_requests = [t for t in self.bot_requests if t > cutoff]
def record_request(self, ip: str, path: str, is_bot: bool, is_blocked: bool = False, is_404: bool = False):
# Request Details cleanup
for ip in list(self.ip_request_details.keys()):
self.ip_request_details[ip] = [r for r in self.ip_request_details[ip] if r['ts'] > cutoff]
if not self.ip_request_details[ip]:
del self.ip_request_details[ip]
def record_request(self, ip: str, path: str, is_bot: bool, is_blocked: bool = False, is_404: bool = False, user_agent: str = ''):
"""Zeichnet einen Request auf."""
now = time.time()
@@ -1389,6 +1399,30 @@ class LiveStatsTracker:
if ip not in self.ip_info:
self.ip_info[ip] = get_ip_info(ip)
# Request Details speichern (für IP-Detail Popup)
if ip not in self.ip_request_details:
self.ip_request_details[ip] = []
self.ip_request_details[ip].append({
'ts': now,
'path': path,
'ua': user_agent,
'blocked': is_blocked
})
# Limitieren auf max_request_details
if len(self.ip_request_details[ip]) > self.max_request_details:
self.ip_request_details[ip] = self.ip_request_details[ip][-self.max_request_details:]
def get_ip_requests(self, ip: str, limit: int = 0) -> List[Dict]:
"""Gibt die Requests einer IP zurück. limit=0 für alle."""
self.cleanup_old_data()
if ip not in self.ip_request_details:
return []
# Neueste zuerst
all_requests = list(reversed(self.ip_request_details[ip]))
if limit > 0:
return all_requests[:limit]
return all_requests
def get_top_ips(self, limit: int = 10) -> List[Dict[str, Any]]:
"""Gibt Top IPs mit Zusatzinfos zurück."""
self.cleanup_old_data()
@@ -3858,6 +3892,13 @@ class JTLWAFiAgent:
if 'Path: ' in line:
path = line.split('Path: ')[1].split(' |')[0].strip()
# User-Agent extrahieren
user_agent = ''
if 'UA: ' in line:
user_agent = line.split('UA: ')[1].split(' |')[0].strip()
elif 'User-Agent: ' in line:
user_agent = line.split('User-Agent: ')[1].split(' |')[0].strip()
# Bot/Human erkennen
is_bot = any(x in line for x in ['BOT: ', 'BOT:', 'BLOCKED_BOT:', 'MONITOR_BOT:', 'BANNED_BOT:'])
@@ -3868,7 +3909,7 @@ class JTLWAFiAgent:
is_404 = '404' in line
if ip:
tracker.record_request(ip, path, is_bot, is_blocked, is_404)
tracker.record_request(ip, path, is_bot, is_blocked, is_404, user_agent)
except Exception as e:
logger.debug(f"LiveStats record error: {e}")
@@ -4490,9 +4531,10 @@ class JTLWAFiAgent:
})
async def _handle_whois_command(self, data: Dict[str, Any]):
"""Führt WHOIS-Lookup für eine IP durch und sendet Ergebnis."""
"""Führt WHOIS-Lookup für eine IP durch und sendet Ergebnis mit Request-Historie."""
command_id = data.get('command_id', 'unknown')
ip = data.get('ip')
shop = data.get('shop') # Optional: für Request-Historie
if not ip:
await self._send_event('whois_result', {
@@ -4506,7 +4548,23 @@ class JTLWAFiAgent:
# WHOIS-Lookup durchführen (wird gecacht)
result = whois_lookup(ip)
# Ergebnis senden (ohne raw für kleinere Payload)
# Request-Historie für diese IP sammeln (aus allen Shops wenn kein Shop angegeben)
requests = []
if shop:
tracker = get_shop_stats_tracker(shop)
requests = tracker.get_ip_requests(ip) # Alle Requests
else:
# Aus allen aktiven Shops sammeln
for s in list(_shop_stats_trackers.keys()):
tracker = get_shop_stats_tracker(s)
shop_requests = tracker.get_ip_requests(ip) # Alle Requests
for r in shop_requests:
r['shop'] = s
requests.extend(shop_requests)
# Nach Zeit sortieren (neueste zuerst)
requests.sort(key=lambda x: x['ts'], reverse=True)
# Ergebnis senden
await self._send_event('whois_result', {
'command_id': command_id,
'success': True,
@@ -4516,10 +4574,11 @@ class JTLWAFiAgent:
'asn': result.get('asn', ''),
'country': result.get('country', ''),
'abuse': result.get('abuse', ''),
'range': result.get('range', '')
'range': result.get('range', ''),
'requests': requests
})
logger.info(f"WHOIS für {ip}: {result.get('org', 'Unknown')} ({result.get('asn', 'N/A')})")
logger.info(f"WHOIS für {ip}: {result.get('org', 'Unknown')} ({result.get('asn', 'N/A')}) - {len(requests)} Requests")
except Exception as e:
logger.error(f"WHOIS Fehler für {ip}: {e}")