ui: netstat/events view improvements

- Clicking on a column will display the details of that item (IP,
   process, etc).
   DstIP, DstPort and UserID columns will open the details of the
   selected item.
   Clicking on the PID column will open the process monitor dialog.
   The rest of the columns will open the details of the process.

 - On the Events tab, clicking on the PID column will open the process
   monitor dialog.
This commit is contained in:
Gustavo Iñiguez Goia 2024-12-21 23:31:25 +01:00
parent 5595a69927
commit 6e7aaf935b
Failed to generate hash of commit
3 changed files with 57 additions and 16 deletions

View file

@ -142,21 +142,21 @@ netstatDelegateConfig = {
"cells": [ "cells": [
{ {
"text": ["LISTEN"], "text": ["LISTEN"],
"cols": [1], "cols": [2],
"color": "green", "color": "green",
"bgcolor": "", "bgcolor": "",
"alignment": ["center"] "alignment": ["center"]
}, },
{ {
"text": ["CLOSE"], "text": ["CLOSE"],
"cols": [1], "cols": [2],
"color": "red", "color": "red",
"bgcolor": "", "bgcolor": "",
"alignment": ["center"] "alignment": ["center"]
}, },
{ {
"text": ["Established"], "text": ["Established"],
"cols": [1], "cols": [2],
"color": "blue", "color": "blue",
"bgcolor": "", "bgcolor": "",
"alignment": ["center"] "alignment": ["center"]
@ -169,7 +169,7 @@ netstatDelegateConfig = {
"TCP_LAST_ACK", "TCP_CLOSING", "TCP_LAST_ACK", "TCP_CLOSING",
"TCP_NEW_SYNC_RECV" "TCP_NEW_SYNC_RECV"
], ],
"cols": [1], "cols": [2],
"color": "", "color": "",
"bgcolor": "", "bgcolor": "",
"alignment": ["center"] "alignment": ["center"]

View file

@ -8,9 +8,9 @@ class NetstatTableModel(GenericTableModel):
def __init__(self, tableName, headerLabels): def __init__(self, tableName, headerLabels):
super().__init__(tableName, headerLabels) super().__init__(tableName, headerLabels)
self.COL_STATE = 1 self.COL_STATE =2
self.COL_PROTO = 6 self.COL_PROTO = 7
self.COL_FAMILY = 8 self.COL_FAMILY = 10
def data(self, index, role=Qt.DisplayRole): def data(self, index, role=Qt.DisplayRole):
"""Paint rows with the data stored in self.items""" """Paint rows with the data stored in self.items"""

View file

@ -95,7 +95,15 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
COL_ALERT_PRIO = 5 COL_ALERT_PRIO = 5
# procs # procs
COL_PID = 9 COL_PROC_PID = 9
# netstat
COL_NET_COMM = 0
COL_NET_PROC = 1
COL_NET_DST_IP = 5
COL_NET_DST_PORT = 6
COL_NET_UID = 8
COL_NET_PID = 9
TAB_MAIN = 0 TAB_MAIN = 0
TAB_NODES = 1 TAB_NODES = 1
@ -313,6 +321,7 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
"model": None, "model": None,
"delegate": "netstatDelegateConfig", "delegate": "netstatDelegateConfig",
"display_fields": "proc_comm as Comm," \ "display_fields": "proc_comm as Comm," \
"proc_path as Process, " \
"state as State, " \ "state as State, " \
"src_port as SrcPort, " \ "src_port as SrcPort, " \
"src_ip as SrcIP, " \ "src_ip as SrcIP, " \
@ -320,9 +329,10 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
"dst_port as DstPort, " \ "dst_port as DstPort, " \
"proto as Protocol, " \ "proto as Protocol, " \
"uid as UID, " \ "uid as UID, " \
"proc_pid as PID, " \
"family as Family, " \ "family as Family, " \
"iface as IFace, " \ "iface as IFace, " \
"'pid:' || proc_pid || ', inode: ' || inode || ', cookies: '|| cookies || ', rqueue: ' || rqueue || ', wqueue: ' || wqueue || ', expires: ' || expires || ', retrans: ' || retrans || ', timer: ' || timer as Metadata ", "'inode: ' || inode || ', cookies: '|| cookies || ', rqueue: ' || rqueue || ', wqueue: ' || wqueue || ', expires: ' || expires || ', retrans: ' || retrans || ', timer: ' || timer as Metadata ",
"header_labels": [], "header_labels": [],
"last_order_by": "2", "last_order_by": "2",
"last_order_to": 1, "last_order_to": 1,
@ -599,12 +609,15 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
self.LAST_NETSTAT_NODE = None self.LAST_NETSTAT_NODE = None
self.TABLES[self.TAB_NETSTAT]['header_labels'] = [ self.TABLES[self.TAB_NETSTAT]['header_labels'] = [
"Comm", "Comm",
self.COL_STR_PROCESS,
QC.translate("stats", "State", "This is a word, without spaces and symbols.").replace(" ", ""), QC.translate("stats", "State", "This is a word, without spaces and symbols.").replace(" ", ""),
QC.translate("stats", "SrcPort", "This is a word, without spaces and symbols.").replace(" ", ""), self.COL_STR_SRC_PORT,
QC.translate("stats", "SrcIP", "This is a word, without spaces and symbols.").replace(" ", ""), self.COL_STR_SRC_IP,
QC.translate("stats", "DstIP", "This is a word, without spaces and symbols.").replace(" ", ""), self.COL_STR_DST_IP,
QC.translate("stats", "DstPort", "This is a word, without spaces and symbols.").replace(" ", ""), self.COL_STR_DST_PORT,
QC.translate("stats", "UID", "This is a word, without spaces and symbols.").replace(" ", ""), self.COL_STR_PROTOCOL,
self.COL_STR_UID,
self.COL_STR_PID,
QC.translate("stats", "Family", "This is a word, without spaces and symbols.").replace(" ", ""), QC.translate("stats", "Family", "This is a word, without spaces and symbols.").replace(" ", ""),
QC.translate("stats", "Iface", "This is a word, without spaces and symbols.").replace(" ", ""), QC.translate("stats", "Iface", "This is a word, without spaces and symbols.").replace(" ", ""),
QC.translate("stats", "Metadata", "This is a word, without spaces and symbols.").replace(" ", "") QC.translate("stats", "Metadata", "This is a word, without spaces and symbols.").replace(" ", "")
@ -1647,7 +1660,7 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
nrows = table.model().rowCount() nrows = table.model().rowCount()
pids = {} pids = {}
for row in range(0, nrows): for row in range(0, nrows):
pid = table.model().index(row, self.COL_PID).data() pid = table.model().index(row, self.COL_PROC_PID).data()
node = table.model().index(row, self.COL_NODE).data() node = table.model().index(row, self.COL_NODE).data()
if pid not in pids: if pid not in pids:
pids[pid] = node pids[pid] = node
@ -1700,7 +1713,6 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
if index == self.TAB_MAIN: if index == self.TAB_MAIN:
self._set_events_query() self._set_events_query()
elif index == self.TAB_NETSTAT: elif index == self.TAB_NETSTAT:
self.IN_DETAIL_VIEW[index] = True
self._monitor_node_netstat() self._monitor_node_netstat()
else: else:
if index == self.TAB_RULES: if index == self.TAB_RULES:
@ -1934,6 +1946,14 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
self._set_active_widgets(prev_idx, True, uid) self._set_active_widgets(prev_idx, True, uid)
self._set_users_query(uid) self._set_users_query(uid)
elif idx == StatsDialog.COL_PID:
node = row.model().index(row.row(), self.COL_NODE).data()
pid = row.model().index(row.row(), self.COL_PID).data()
self.LAST_SELECTED_ITEM = pid
self._proc_details_dialog.monitor(
{pid: node}
)
return
else: else:
cur_idx = self.TAB_PROCS cur_idx = self.TAB_PROCS
self.IN_DETAIL_VIEW[cur_idx] = True self.IN_DETAIL_VIEW[cur_idx] = True
@ -2011,7 +2031,28 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
if cur_idx > self.TAB_RULES: if cur_idx > self.TAB_RULES:
self.LAST_SELECTED_ITEM = row.model().index(row.row(), self.COL_WHAT).data() self.LAST_SELECTED_ITEM = row.model().index(row.row(), self.COL_WHAT).data()
data = row.model().index(row.row(), self.COL_WHAT).data() data = row.model().index(row.row(), self.COL_WHAT).data()
if cur_idx == self.TAB_NETSTAT:
self.IN_DETAIL_VIEW[cur_idx] = False
if row.column() == self.COL_NET_DST_IP:
cur_idx = StatsDialog.TAB_ADDRS
data = row.model().index(row.row(), self.COL_NET_DST_IP).data()
elif row.column() == self.COL_NET_DST_PORT:
cur_idx = StatsDialog.TAB_PORTS
data = row.model().index(row.row(), self.COL_NET_DST_PORT).data()
elif row.column() == self.COL_NET_UID:
cur_idx = StatsDialog.TAB_USERS
data = row.model().index(row.row(), self.COL_NET_UID).data()
elif row.column() == self.COL_NET_PID:
pid = row.model().index(row.row(), self.COL_NET_PID).data()
self._proc_details_dialog.monitor({pid: self.comboNetstatNodes.currentText()})
return
else:
cur_idx = StatsDialog.TAB_PROCS
data = row.model().index(row.row(), self.COL_NET_PROC).data()
if data == "":
return
self.tabWidget.setCurrentIndex(cur_idx)
self._set_active_widgets(cur_idx, True, str(data)) self._set_active_widgets(cur_idx, True, str(data))