328
src/app/api/logs/route.ts
Archivo normal
328
src/app/api/logs/route.ts
Archivo normal
@@ -0,0 +1,328 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { exec } from 'child_process'
|
||||
import { promisify } from 'util'
|
||||
import fs from 'fs/promises'
|
||||
|
||||
const execAsync = promisify(exec)
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const { searchParams } = new URL(request.url)
|
||||
const type = searchParams.get('type')
|
||||
const limit = parseInt(searchParams.get('limit') || '100')
|
||||
const since = searchParams.get('since') // timestamp
|
||||
|
||||
try {
|
||||
switch (type) {
|
||||
case 'firewall':
|
||||
return await getFirewallLogs(limit, since)
|
||||
|
||||
case 'lfd':
|
||||
return await getLfdLogs(limit, since)
|
||||
|
||||
case 'system':
|
||||
return await getSystemLogs(limit, since)
|
||||
|
||||
case 'blocked':
|
||||
return await getBlockedIPs(limit)
|
||||
|
||||
case 'connections':
|
||||
return await getActiveConnections()
|
||||
|
||||
default:
|
||||
return await getAllLogs(limit, since)
|
||||
}
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('Logs API error:', error)
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: `Failed to retrieve logs: ${error.message}`
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
async function getFirewallLogs(limit: number, since?: string) {
|
||||
try {
|
||||
// Get iptables logs from syslog
|
||||
let command = `grep "CSF\\|iptables" /var/log/syslog | tail -${limit}`
|
||||
if (since) {
|
||||
const sinceDate = new Date(since).toISOString().split('T')[0]
|
||||
command = `grep "CSF\\|iptables" /var/log/syslog | grep "${sinceDate}" | tail -${limit}`
|
||||
}
|
||||
|
||||
const { stdout } = await execAsync(command)
|
||||
const logs = parseFirewallLogs(stdout)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: {
|
||||
logs,
|
||||
total: logs.length,
|
||||
type: 'firewall'
|
||||
}
|
||||
})
|
||||
} catch (error: any) {
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: `Failed to get firewall logs: ${error.message}`
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
async function getLfdLogs(limit: number, since?: string) {
|
||||
try {
|
||||
let command = `grep "lfd" /var/log/lfd.log 2>/dev/null | tail -${limit} || echo ""`
|
||||
if (since) {
|
||||
const sinceDate = new Date(since).toISOString().split('T')[0]
|
||||
command = `grep "lfd" /var/log/lfd.log 2>/dev/null | grep "${sinceDate}" | tail -${limit} || echo ""`
|
||||
}
|
||||
|
||||
const { stdout } = await execAsync(command)
|
||||
const logs = parseLfdLogs(stdout)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: {
|
||||
logs,
|
||||
total: logs.length,
|
||||
type: 'lfd'
|
||||
}
|
||||
})
|
||||
} catch (error: any) {
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: `Failed to get LFD logs: ${error.message}`
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
async function getSystemLogs(limit: number, since?: string) {
|
||||
try {
|
||||
let command = `grep "kernel\\|iptables" /var/log/syslog | tail -${limit}`
|
||||
if (since) {
|
||||
const sinceDate = new Date(since).toISOString().split('T')[0]
|
||||
command = `grep "kernel\\|iptables" /var/log/syslog | grep "${sinceDate}" | tail -${limit}`
|
||||
}
|
||||
|
||||
const { stdout } = await execAsync(command)
|
||||
const logs = parseSystemLogs(stdout)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: {
|
||||
logs,
|
||||
total: logs.length,
|
||||
type: 'system'
|
||||
}
|
||||
})
|
||||
} catch (error: any) {
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: `Failed to get system logs: ${error.message}`
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
async function getBlockedIPs(limit: number) {
|
||||
try {
|
||||
// Get current blocked IPs from iptables
|
||||
const { stdout } = await execAsync('/usr/local/csf/bin/csf --status | grep DROP | head -' + limit)
|
||||
const blockedIPs = parseBlockedIPs(stdout)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: {
|
||||
blocked_ips: blockedIPs,
|
||||
total: blockedIPs.length,
|
||||
type: 'blocked'
|
||||
}
|
||||
})
|
||||
} catch (error: any) {
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: `Failed to get blocked IPs: ${error.message}`
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
async function getActiveConnections() {
|
||||
try {
|
||||
// Get active network connections
|
||||
const { stdout } = await execAsync('netstat -tn | grep ESTABLISHED | wc -l')
|
||||
const activeConnections = parseInt(stdout.trim()) || 0
|
||||
|
||||
// Get connection details
|
||||
const { stdout: connections } = await execAsync('netstat -tn | grep ESTABLISHED | head -20')
|
||||
const connectionList = parseConnections(connections)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: {
|
||||
active_connections: activeConnections,
|
||||
connections: connectionList,
|
||||
type: 'connections'
|
||||
}
|
||||
})
|
||||
} catch (error: any) {
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: `Failed to get active connections: ${error.message}`
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
async function getAllLogs(limit: number, since?: string) {
|
||||
try {
|
||||
const [firewallResult, lfdResult, systemResult] = await Promise.allSettled([
|
||||
getFirewallLogs(Math.floor(limit / 3), since),
|
||||
getLfdLogs(Math.floor(limit / 3), since),
|
||||
getSystemLogs(Math.floor(limit / 3), since)
|
||||
])
|
||||
|
||||
const allLogs = []
|
||||
|
||||
if (firewallResult.status === 'fulfilled') {
|
||||
const response = await firewallResult.value.json()
|
||||
if (response.success) allLogs.push(...response.data.logs)
|
||||
}
|
||||
|
||||
if (lfdResult.status === 'fulfilled') {
|
||||
const response = await lfdResult.value.json()
|
||||
if (response.success) allLogs.push(...response.data.logs)
|
||||
}
|
||||
|
||||
if (systemResult.status === 'fulfilled') {
|
||||
const response = await systemResult.value.json()
|
||||
if (response.success) allLogs.push(...response.data.logs)
|
||||
}
|
||||
|
||||
// Sort by timestamp
|
||||
allLogs.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime())
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: {
|
||||
logs: allLogs.slice(0, limit),
|
||||
total: allLogs.length,
|
||||
type: 'all'
|
||||
}
|
||||
})
|
||||
} catch (error: any) {
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: `Failed to get all logs: ${error.message}`
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
// Parsing functions
|
||||
function parseFirewallLogs(output: string) {
|
||||
const logs = []
|
||||
const lines = output.split('\\n').filter(line => line.trim())
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i]
|
||||
const logEntry = parseLogLine(line, 'firewall')
|
||||
if (logEntry) logs.push(logEntry)
|
||||
}
|
||||
|
||||
return logs
|
||||
}
|
||||
|
||||
function parseLfdLogs(output: string) {
|
||||
const logs = []
|
||||
const lines = output.split('\\n').filter(line => line.trim())
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i]
|
||||
const logEntry = parseLogLine(line, 'lfd')
|
||||
if (logEntry) logs.push(logEntry)
|
||||
}
|
||||
|
||||
return logs
|
||||
}
|
||||
|
||||
function parseSystemLogs(output: string) {
|
||||
const logs = []
|
||||
const lines = output.split('\\n').filter(line => line.trim())
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i]
|
||||
const logEntry = parseLogLine(line, 'system')
|
||||
if (logEntry) logs.push(logEntry)
|
||||
}
|
||||
|
||||
return logs
|
||||
}
|
||||
|
||||
function parseLogLine(line: string, type: string) {
|
||||
// Basic log parsing - adjust regex patterns based on actual log format
|
||||
const patterns = {
|
||||
timestamp: /^(\\w{3}\\s+\\d{1,2}\\s+\\d{2}:\\d{2}:\\d{2})/,
|
||||
ip: /(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})/,
|
||||
port: /DPT=(\\d+)/,
|
||||
protocol: /(TCP|UDP|ICMP)/i,
|
||||
action: /(BLOCK|DROP|ACCEPT|ALLOW|DENY)/i
|
||||
}
|
||||
|
||||
const timestampMatch = line.match(patterns.timestamp)
|
||||
const ipMatch = line.match(patterns.ip)
|
||||
const portMatch = line.match(patterns.port)
|
||||
const protocolMatch = line.match(patterns.protocol)
|
||||
const actionMatch = line.match(patterns.action)
|
||||
|
||||
if (!timestampMatch) return null
|
||||
|
||||
const currentYear = new Date().getFullYear()
|
||||
const timestamp = new Date(`${currentYear} ${timestampMatch[1]}`).toISOString()
|
||||
|
||||
return {
|
||||
id: `${type}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
||||
timestamp,
|
||||
level: actionMatch && (actionMatch[1].toLowerCase() === 'block' || actionMatch[1].toLowerCase() === 'drop') ? 'block' : 'info',
|
||||
message: line,
|
||||
ip: ipMatch ? ipMatch[1] : undefined,
|
||||
port: portMatch ? portMatch[1] : undefined,
|
||||
protocol: protocolMatch ? protocolMatch[1].toUpperCase() : undefined,
|
||||
action: actionMatch ? actionMatch[1].toUpperCase() : undefined,
|
||||
type
|
||||
}
|
||||
}
|
||||
|
||||
function parseBlockedIPs(output: string) {
|
||||
const blockedIPs = []
|
||||
const lines = output.split('\\n').filter(line => line.trim())
|
||||
|
||||
for (const line of lines) {
|
||||
const ipMatch = line.match(/(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})/)
|
||||
if (ipMatch) {
|
||||
blockedIPs.push({
|
||||
ip: ipMatch[1],
|
||||
reason: 'Firewall rule',
|
||||
timestamp: new Date().toISOString()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return blockedIPs
|
||||
}
|
||||
|
||||
function parseConnections(output: string) {
|
||||
const connections = []
|
||||
const lines = output.split('\\n').filter(line => line.trim())
|
||||
|
||||
for (const line of lines) {
|
||||
const parts = line.trim().split(/\\s+/)
|
||||
if (parts.length >= 4) {
|
||||
const [protocol, , , localAddress, foreignAddress] = parts
|
||||
connections.push({
|
||||
protocol,
|
||||
local_address: localAddress,
|
||||
foreign_address: foreignAddress,
|
||||
state: 'ESTABLISHED'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return connections
|
||||
}
|
||||
Referencia en una nueva incidencia
Block a user