package com.aluer.security; import org.springframework.stereotype.Service; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; import java.security.MessageDigest; @Service public class FirewallService { private final Map rules = new ConcurrentHashMap<>(); private final Map profiles = new ConcurrentHashMap<>(); private final Map connections = new ConcurrentHashMap<>(); private final Queue logs = new ConcurrentLinkedQueue<>(); private final Set whitelist = ConcurrentHashMap.newKeySet(); private final Set blacklist = ConcurrentHashMap.newKeySet(); private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2); private volatile FirewallProfile activeProfile; private final AtomicLong ruleIdCounter = new AtomicLong(1); public static final int MAX_CONNECTIONS = 10000; public static final long CONNECTION_TIMEOUT = 120000; public static final int MAX_RULES = 500; public FirewallService() { initializeDefaultRules(); initializeDefaultProfiles(); startCleanupTask(); } private void initializeDefaultProfiles() { FirewallProfile strict = new FirewallProfile("strict", "严格模式", true); strict.maxConnectionsPerIP = 10; strict.maxRequestsPerSecond = 20; strict.blockPingFlood = true; strict.blockPortScan = true; strict.blockSQLInjection = true; strict.blockXSS = true; profiles.put("strict", strict); FirewallProfile normal = new FirewallProfile("normal", "普通模式", false); normal.maxConnectionsPerIP = 50; normal.maxRequestsPerSecond = 100; normal.blockPingFlood = false; normal.blockPortScan = true; normal.blockSQLInjection = true; normal.blockXSS = true; profiles.put("normal", normal); FirewallProfile relaxed = new FirewallProfile("relaxed", "宽松模式", false); relaxed.maxConnectionsPerIP = 100; relaxed.maxRequestsPerSecond = 500; relaxed.blockPingFlood = false; relaxed.blockPortScan = false; relaxed.blockSQLInjection = false; relaxed.blockXSS = false; profiles.put("relaxed", relaxed); activeProfile = normal; } private void initializeDefaultRules() { addRule("DROP", "tcp", "0.0.0.0/0", "0.0.0.0/0", 23, "Telnet", "BLOCK_TELNET"); addRule("DROP", "tcp", "0.0.0.0/0", "0.0.0.0/0", 445, "SMB", "BLOCK_SMB"); addRule("DROP", "udp", "0.0.0.0/0", "0.0.0.0/0", 137, "NetBIOS", "BLOCK_NETBIOS"); addRule("DROP", "udp", "0.0.0.0/0", "0.0.0.0/0", 138, "NetBIOS", "BLOCK_NETBIOS"); addRule("DROP", "tcp", "0.0.0.0/0", "0.0.0.0/0", 1433, "MSSQL", "BLOCK_MSSQL"); addRule("DROP", "tcp", "0.0.0.0/0", "0.0.0.0/0", 3306, "MySQL", "BLOCK_MYSQL"); addRule("DROP", "tcp", "0.0.0.0/0", "0.0.0.0/0", 5432, "PostgreSQL", "BLOCK_POSTGRESQL"); addRule("DROP", "tcp", "0.0.0.0/0", "0.0.0.0/0", 27017, "MongoDB", "BLOCK_MONGODB"); } public long addRule(String action, String protocol, String sourceIP, String destIP, int port, String description, String category) { if (rules.size() >= MAX_RULES) { return -1; } long id = ruleIdCounter.getAndIncrement(); FirewallRule rule = new FirewallRule(id, action, protocol, sourceIP, destIP, port, description, category); rules.put(String.valueOf(id), rule); logRuleChange("ADD", id, rule); return id; } public boolean removeRule(long ruleId) { String key = String.valueOf(ruleId); FirewallRule removed = rules.remove(key); if (removed != null) { logRuleChange("REMOVE", ruleId, removed); return true; } return false; } public FirewallRule getRule(long ruleId) { return rules.get(String.valueOf(ruleId)); } public Collection getAllRules() { return rules.values(); } public boolean updateRule(long ruleId, FirewallRule updated) { String key = String.valueOf(ruleId); if (!rules.containsKey(key)) { return false; } rules.put(key, updated); logRuleChange("UPDATE", ruleId, updated); return true; } public boolean checkConnection(String sourceIP, String destIP, int port, String protocol) { if (whitelist.contains(sourceIP)) { return true; } if (blacklist.contains(sourceIP)) { logBlock(sourceIP, destIP, port, "BLACKLIST"); return false; } FirewallProfile profile = activeProfile; if (profile == null) { return true; } for (FirewallRule rule : rules.values()) { if (rule.matches(protocol, sourceIP, destIP, port)) { if ("DROP".equals(rule.action) || "DENY".equals(rule.action)) { logBlock(sourceIP, destIP, port, rule.category); return false; } } } if (profile.maxConnectionsPerIP > 0) { int connCount = getConnectionCount(sourceIP); if (connCount >= profile.maxConnectionsPerIP) { logBlock(sourceIP, destIP, port, "CONNECTION_LIMIT"); return false; } } return true; } public boolean checkRequest(String ip, String request) { FirewallProfile profile = activeProfile; if (profile == null) { return true; } if (profile.blockSQLInjection && containsSQLInjection(request)) { logBlock(ip, "REQUEST", 0, "SQL_INJECTION"); return false; } if (profile.blockXSS && containsXSS(request)) { logBlock(ip, "REQUEST", 0, "XSS"); return false; } if (profile.blockPathTraversal && containsPathTraversal(request)) { logBlock(ip, "REQUEST", 0, "PATH_TRAVERSAL"); return false; } return true; } private boolean containsSQLInjection(String input) { if (input == null) return false; String lower = input.toLowerCase(); String[] sqlKeywords = {"union", "select", "insert", "update", "delete", "drop", "create", "alter", "exec", "execute", "script", "--", ";"}; for (String keyword : sqlKeywords) { if (lower.contains(keyword)) { return true; } } return false; } private boolean containsXSS(String input) { if (input == null) return false; String[] xssPatterns = {" getAllProfiles() { return profiles.values(); } public void recordConnection(String ip, String destIP, int port, String protocol) { String key = ip + ":" + destIP + ":" + port; connections.put(key, new ConnectionState(ip, destIP, port, protocol)); } public void closeConnection(String ip, String destIP, int port) { String key = ip + ":" + destIP + ":" + port; connections.remove(key); } public int getConnectionCount(String ip) { return (int) connections.keySet().stream() .filter(k -> k.startsWith(ip + ":")) .count(); } public Collection getActiveConnections() { return connections.values(); } private void logBlock(String sourceIP, String destIP, int port, String reason) { FirewallLog log = new FirewallLog("BLOCK", sourceIP, destIP, port, reason, System.currentTimeMillis()); addLog(log); } private void logRuleChange(String action, long ruleId, FirewallRule rule) { FirewallLog log = new FirewallLog("RULE_" + action, rule.sourceIP, rule.destIP, rule.port, ruleId + ":" + rule.description, System.currentTimeMillis()); addLog(log); } private void logConfigChange(String action, String details) { FirewallLog log = new FirewallLog("CONFIG_" + action, "SYSTEM", details, 0, "", System.currentTimeMillis()); addLog(log); } private void addLog(FirewallLog log) { logs.offer(log); while (logs.size() > 5000) { logs.remove(); } } public List getLogs(int limit) { List result = new ArrayList<>(); int count = 0; for (FirewallLog log : logs) { if (count++ >= limit) break; result.add(log); } return result; } public Map getStats() { Map stats = new HashMap<>(); stats.put("totalRules", rules.size()); stats.put("whitelistSize", whitelist.size()); stats.put("blacklistSize", blacklist.size()); stats.put("activeConnections", connections.size()); stats.put("activeProfile", activeProfile != null ? activeProfile.name : "none"); return stats; } private void startCleanupTask() { scheduler.scheduleAtFixedRate(() -> { long now = System.currentTimeMillis(); connections.entrySet().removeIf(entry -> now - entry.getValue().createdAt > CONNECTION_TIMEOUT); }, 60, 60, TimeUnit.SECONDS); } public static class FirewallRule { public final long id; public final String action; public final String protocol; public final String sourceIP; public final String destIP; public final int port; public final String description; public final String category; public final long createdAt; public FirewallRule(long id, String action, String protocol, String sourceIP, String destIP, int port, String description, String category) { this.id = id; this.action = action; this.protocol = protocol; this.sourceIP = sourceIP; this.destIP = destIP; this.port = port; this.description = description; this.category = category; this.createdAt = System.currentTimeMillis(); } public boolean matches(String protocol, String sourceIP, String destIP, int port) { if (!this.protocol.equalsIgnoreCase(protocol) && !this.protocol.equals("*")) { return false; } if (this.port != 0 && this.port != port) { return false; } return true; } } public static class FirewallProfile { public final String name; public final String description; public final boolean isDefault; public int maxConnectionsPerIP = 50; public int maxRequestsPerSecond = 100; public boolean blockPingFlood = false; public boolean blockPortScan = false; public boolean blockSQLInjection = false; public boolean blockXSS = false; public boolean blockPathTraversal = false; public FirewallProfile(String name, String description, boolean isDefault) { this.name = name; this.description = description; this.isDefault = isDefault; } } public static class ConnectionState { public final String sourceIP; public final String destIP; public final int port; public final String protocol; public final long createdAt; public volatile long lastActivity; public ConnectionState(String sourceIP, String destIP, int port, String protocol) { this.sourceIP = sourceIP; this.destIP = destIP; this.port = port; this.protocol = protocol; this.createdAt = System.currentTimeMillis(); this.lastActivity = System.currentTimeMillis(); } } public static class FirewallLog { public final String type; public final String sourceIP; public final String destIP; public final int port; public final String reason; public final long timestamp; public FirewallLog(String type, String sourceIP, String destIP, int port, String reason, long timestamp) { this.type = type; this.sourceIP = sourceIP; this.destIP = destIP; this.port = port; this.reason = reason; this.timestamp = timestamp; } } }