Skip to main content
The SOC dashboard (interfasc.py) is the operator-facing window of the IDS/IPS system. It is built with PyQt5 and embeds Matplotlib charts. All IDS→UI updates flow through Qt signals, making every update thread-safe without manual locking.

Performance constants

interfasc.py
MAX_EVENTOS_TABLA   = 1000   # Maximum rows visible in the events table
MAX_EVENTOS_MEMORIA = 10000  # Maximum events in the in-memory deque
MAX_TRAFICO_LINEAS  = 500    # Maximum lines in the "Tráfico en Vivo" panel
UPDATE_BATCH_SIZE   = 50     # Events processed per DataProcessor cycle
These constants prevent the UI from becoming unresponsive during sustained attacks. When a table reaches its limit, older rows are pruned from the visible view; the underlying deque still holds up to MAX_EVENTOS_MEMORIA events for in-session statistics.

Main window tabs

Tráfico en Vivo

A QPlainTextEdit in read-only mode that displays one line per captured packet. Each line is the output of Scapy’s packet.summary(). The buffer is capped at MAX_TRAFICO_LINEAS = 500 lines via a deque(maxlen=500) — when full, the oldest line is discarded automatically. New lines arrive via the nuevo_trafico Qt signal emitted from ids.py on every captured packet, regardless of whether a threat was detected.

Events table

A QTableWidget with up to MAX_EVENTOS_TABLA = 1000 rows. Each row corresponds to a detected attack event and has seven columns:
#ColumnSource field
0Horaevento[0]time.ctime() timestamp
1IP Origenevento[1] — attacker source IP
2IP Destinoevento[2] — targeted destination IP
3Puertoevento[3] — destination port
4Protocoloevento[4]"TCP" or "UDP"
5Flagevento[5] — TCP flag string
6Tipo de Ataqueevento[6] — heuristic or ML label
Each row is color-coded using ATTACK_STYLE (see below). The table supports real-time text search across all columns and severity filtering via a QComboBox.

IPS panel

A 7-column SOC table that tracks every block event:
#ColumnDescription
0HoraTimestamp of the block event
1IP BloqueadaThe blocked source IP
2Tipo de AtaqueAttack label that triggered the block
3SeveridadCRITICA / ALTA / MEDIA
4Acción Aplicada"Bloqueo real" or "Bloqueo simulado"
5EstadoACTIVO / SIMULADO / Expirado / Desbloqueado
6Tiempo RestanteLive countdown in MM:SS format
The countdown is driven by a QTimer that fires every second. When it reaches zero, the row status changes to "Expirado" automatically. Manual unblock via the Desbloquear button marks the row "Desbloqueado" in blue without deleting it, preserving a visible audit trail.
Rows in the IPS panel are never deleted during a session. The "Desbloqueado" and "Expirado" states provide a persistent in-session block history for SOC analysts.

Charts tab

Matplotlib figures are embedded using FigureCanvasQTAgg:
interfasc.py
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
The dark background style is activated globally with style.use('dark_background'). Charts are refreshed on a timer rather than on every event to avoid continuous repaints during high-traffic conditions.

Attack color mapping

interfasc.py
ATTACK_STYLE = {
    "Inyección SQL":  {"color": "#ff5370"},  # Red
    "PORT scanner":   {"color": "#bb86fc"},  # Violet
    "DDOS":           {"color": "#00eaff"},  # Cyan
    "SYN FLOOD":      {"color": "#82b1ff"},  # Light blue
    "UDP Flood":      {"color": "#ffa000"},  # Amber
}
These colors are applied as cell background/foreground in the events table. The colors_for_labels() function extends this mapping to the pie chart — unknown attack types receive a deterministic color from the tab20 Matplotlib colormap based on hash(label) % 20.

Controls

ControlTypeAction
Start monitoringQPushButtonCalls ids.iniciar_monitoreo(iface) with the selected interface
Stop monitoringQPushButtonCalls ids.detener_monitoreo()
Interface selectorQComboBoxLists available network interfaces via Scapy
IPS toggleQCheckBoxSets ids.ips_activo = True/False directly
Export to CSVQPushButtonOpens QFileDialog and writes all in-memory events to a .csv file
SearchQLineEditFilters visible table rows matching any column
Severity filterQComboBoxShows only rows of the selected severity level (Todos / CRÍTICA / ALTA / MEDIA / BAJA)

Thread safety

All IDS-to-UI data flow goes through Qt signals:
Scapy sniffer thread
    └─ ids.procesar_paquete()
          ├─ comunicador.nuevo_trafico.emit(str)   → live traffic panel
          └─ guardar_ataque()
                ├─ comunicador.nuevo_evento.emit(list)  → events table
                └─ comunicador.nuevo_bloqueo.emit(list) → IPS panel
Qt delivers signals across thread boundaries by posting to the receiver’s thread’s event queue. The GUI thread processes these events on its next event-loop iteration. No manual mutexes are needed for the signal payloads themselves. An intermediate DataProcessor (QThread) batches incoming events to avoid flooding the Qt event loop during burst traffic:
interfasc.py
class DataProcessor(QThread):
    data_ready  = pyqtSignal(list)   # emits a batch of up to UPDATE_BATCH_SIZE events
    stats_ready = pyqtSignal(dict)   # emits updated SOC statistics

    def run(self):
        while self.running:
            if self.pending_events:
                batch = []  # collect up to UPDATE_BATCH_SIZE
                ...
                self.data_ready.emit(batch)
                self.stats_ready.emit(stats)
            self.msleep(100)  # 100ms polling interval
The data_lock threading.Lock in interfasc.py protects the shared eventos_detectados deque and advertencias_cont dict from concurrent reads (DataProcessor) and writes (signal slots in the main thread). This is separate from the Qt signal mechanism.

Build docs developers (and LLMs) love