packetsnitch 1.5.599
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +28 -0
- package/.webpack/x64/main/index.js +2 -0
- package/.webpack/x64/main/index.js.map +1 -0
- package/.webpack/x64/renderer/assets/css/rubikglitch.woff2 +0 -0
- package/.webpack/x64/renderer/assets/css/style.css +1916 -0
- package/.webpack/x64/renderer/assets/images/loading.gif +0 -0
- package/.webpack/x64/renderer/assets/images/logo.webp +0 -0
- package/.webpack/x64/renderer/assets/images/packet-snitch-tag.webp +0 -0
- package/.webpack/x64/renderer/main_window/index.html +3 -0
- package/.webpack/x64/renderer/main_window/index.js +3 -0
- package/.webpack/x64/renderer/main_window/index.js.LICENSE.txt +36 -0
- package/.webpack/x64/renderer/main_window/index.js.map +1 -0
- package/.webpack/x64/renderer/main_window/preload.js +2 -0
- package/.webpack/x64/renderer/main_window/preload.js.map +1 -0
- package/backend/common/GeoLite2-City.mmdb +0 -0
- package/backend/common/mac-vendors-export.csv +56923 -0
- package/backend/common/service-names-port-numbers.csv +15368 -0
- package/backend/requirements.txt +14 -0
- package/backend/snitch.py +3611 -0
- package/forge.config.js +80 -0
- package/package.json +102 -0
- package/ps-icon.ico +0 -0
- package/snitch.spec +44 -0
- package/src/assets/css/rubikglitch.woff2 +0 -0
- package/src/assets/css/style.css +1916 -0
- package/src/assets/images/loading.gif +0 -0
- package/src/assets/images/logo.webp +0 -0
- package/src/assets/images/packet-snitch-tag.webp +0 -0
- package/src/back-comm.js +70 -0
- package/src/decoders.js +579 -0
- package/src/filter.js +461 -0
- package/src/front.js +10 -0
- package/src/index.html +1036 -0
- package/src/logging.js +150 -0
- package/src/main.js +571 -0
- package/src/preload.js +73 -0
- package/src/renderer.js +30 -0
- package/src/ui/common-frontend.js +13 -0
- package/src/ui/context-menu.js +88 -0
- package/src/ui/decoders.js +1 -0
- package/src/ui/main-frontend.js +4957 -0
- package/src/ui/panels/crypt-panel.js +565 -0
- package/src/ui/panels/data-panel.js +151 -0
- package/src/ui/panels/data-tools-panel.js +939 -0
- package/src/ui/panels/install-screen.js +59 -0
- package/src/ui/panels/keystore-panel.js +1248 -0
- package/src/ui/panels/list-panel.js +403 -0
- package/src/ui/panels/stats-panel.js +351 -0
- package/src/ui/panels/summary-panel.js +63 -0
- package/webpack.main.config.js +11 -0
- package/webpack.plugins.js +13 -0
- package/webpack.preload.config.js +7 -0
- package/webpack.renderer.config.js +30 -0
- package/webpack.rules.js +35 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/src/back-comm.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const { BrowserWindow, ipcMain } = require('electron');
|
|
2
|
+
const { exec } = require('child_process');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const platform = os.platform();
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const systemTempDir = os.tmpdir();
|
|
8
|
+
const testcaseOutputDir = path.join(systemTempDir, 'testcases');
|
|
9
|
+
ipcMain.handle('run-backend-command', async (event, filename, useLLM) => {
|
|
10
|
+
global.logBackend(`Received pcap: ${filename}`);
|
|
11
|
+
const isDev = !require('electron').app.isPackaged;
|
|
12
|
+
const basePath = isDev
|
|
13
|
+
? path.join(__dirname, '../..')
|
|
14
|
+
: process.resourcesPath;
|
|
15
|
+
let snitchExePath;
|
|
16
|
+
|
|
17
|
+
if (platform === 'win32') {
|
|
18
|
+
snitchExePath = path.join(basePath, '\\backend\\snitch\\snitch.exe');
|
|
19
|
+
} else if (platform === 'linux') {
|
|
20
|
+
snitchExePath = path.join(basePath, '/backend/snitch/snitch');
|
|
21
|
+
} else {
|
|
22
|
+
snitchExePath = path.join(basePath, '/backend/snitch/snitch');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const backendCommand = `"${snitchExePath}" "${filename}" -a -o "${testcaseOutputDir}"${useLLM ? '' : ' --nollm'}`;
|
|
26
|
+
|
|
27
|
+
// Always start with a clean output directory so snitch never hits the
|
|
28
|
+
// interactive overwrite prompt on second (and later) runs.
|
|
29
|
+
if (fs.existsSync(testcaseOutputDir)) {
|
|
30
|
+
fs.rmSync(testcaseOutputDir, { recursive: true, force: true });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
global.logBackend('Command to run:', backendCommand);
|
|
34
|
+
|
|
35
|
+
function sendError(message) {
|
|
36
|
+
const mainWin = BrowserWindow.getAllWindows()[0]; // or track your main window
|
|
37
|
+
if (mainWin) {
|
|
38
|
+
mainWin.webContents.send('backend-error', message);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return new Promise((resolve) => {
|
|
43
|
+
exec(backendCommand, (error, stdout, stderr) => {
|
|
44
|
+
resolve(stdout);
|
|
45
|
+
global.logBackend('Backend output:', stdout);
|
|
46
|
+
global.logBackend('Backend error output:', stderr);
|
|
47
|
+
if (stdout.includes('Ollama')) {
|
|
48
|
+
sendError('Backend LLM generation error!');
|
|
49
|
+
}
|
|
50
|
+
if (error) {
|
|
51
|
+
if (stderr.includes('supported capture file')) {
|
|
52
|
+
sendError('Unsupported file format!');
|
|
53
|
+
} else {
|
|
54
|
+
sendError('Backend execution error! ' + error);
|
|
55
|
+
}
|
|
56
|
+
} else {
|
|
57
|
+
setTimeout(() => {
|
|
58
|
+
const hostsJsonPath = path.join(testcaseOutputDir, 'hosts.json');
|
|
59
|
+
const mainWin = BrowserWindow.getAllWindows()[0];
|
|
60
|
+
if (mainWin && fs.existsSync(hostsJsonPath)) {
|
|
61
|
+
const hostsJsonData = fs.readFileSync(hostsJsonPath, 'utf8');
|
|
62
|
+
mainWin.webContents.send('json-data', hostsJsonData);
|
|
63
|
+
}
|
|
64
|
+
}, 200);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
global.logBackend('Backend started, waiting for completion...');
|
|
69
|
+
});
|
|
70
|
+
});
|
package/src/decoders.js
ADDED
|
@@ -0,0 +1,579 @@
|
|
|
1
|
+
// Protocol decoder render functions for the info panel side tables.
|
|
2
|
+
// Each function reads the relevant sub-object from transportData and appends
|
|
3
|
+
// a table to the "sidedatatable" container (or no-ops when the data is absent).
|
|
4
|
+
|
|
5
|
+
// Reusable element pools to reduce garbage collection
|
|
6
|
+
const elementPool = {
|
|
7
|
+
table: null,
|
|
8
|
+
tr: null,
|
|
9
|
+
th: null,
|
|
10
|
+
td: null,
|
|
11
|
+
reset() {
|
|
12
|
+
this.table = null;
|
|
13
|
+
this.tr = null;
|
|
14
|
+
this.th = null;
|
|
15
|
+
this.td = null;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
function createTable(data, headers, containerId) {
|
|
20
|
+
const container = document.getElementById(containerId);
|
|
21
|
+
if (!container) return;
|
|
22
|
+
|
|
23
|
+
// Use DocumentFragment for batched DOM insertion
|
|
24
|
+
const fragment = document.createDocumentFragment();
|
|
25
|
+
|
|
26
|
+
const table = document.createElement('table');
|
|
27
|
+
const headerRow = document.createElement('tr');
|
|
28
|
+
for (let i = 0; i < headers.length; i++) {
|
|
29
|
+
const th = document.createElement('th');
|
|
30
|
+
th.textContent = headers[i];
|
|
31
|
+
headerRow.appendChild(th);
|
|
32
|
+
}
|
|
33
|
+
table.appendChild(headerRow);
|
|
34
|
+
|
|
35
|
+
// Build all rows first, then append once
|
|
36
|
+
for (let i = 0; i < data.length; i++) {
|
|
37
|
+
const item = data[i];
|
|
38
|
+
const row = document.createElement('tr');
|
|
39
|
+
const values = Object.values(item);
|
|
40
|
+
for (let j = 0; j < values.length; j++) {
|
|
41
|
+
const td = document.createElement('td');
|
|
42
|
+
td.textContent = values[j];
|
|
43
|
+
row.appendChild(td);
|
|
44
|
+
}
|
|
45
|
+
table.appendChild(row);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
fragment.appendChild(table);
|
|
49
|
+
container.appendChild(fragment);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Optimized batch table creation for multiple tables
|
|
53
|
+
function createTablesBatch(tablesData, containerId) {
|
|
54
|
+
const container = document.getElementById(containerId);
|
|
55
|
+
if (!container) return;
|
|
56
|
+
|
|
57
|
+
const fragment = document.createDocumentFragment();
|
|
58
|
+
|
|
59
|
+
for (const tableData of tablesData) {
|
|
60
|
+
const table = document.createElement('table');
|
|
61
|
+
const headerRow = document.createElement('tr');
|
|
62
|
+
for (let i = 0; i < tableData.headers.length; i++) {
|
|
63
|
+
const th = document.createElement('th');
|
|
64
|
+
th.textContent = tableData.headers[i];
|
|
65
|
+
headerRow.appendChild(th);
|
|
66
|
+
}
|
|
67
|
+
table.appendChild(headerRow);
|
|
68
|
+
|
|
69
|
+
for (let i = 0; i < tableData.rows.length; i++) {
|
|
70
|
+
const item = tableData.rows[i];
|
|
71
|
+
const row = document.createElement('tr');
|
|
72
|
+
const values = Object.values(item);
|
|
73
|
+
for (let j = 0; j < values.length; j++) {
|
|
74
|
+
const td = document.createElement('td');
|
|
75
|
+
td.textContent = values[j];
|
|
76
|
+
row.appendChild(td);
|
|
77
|
+
}
|
|
78
|
+
table.appendChild(row);
|
|
79
|
+
}
|
|
80
|
+
fragment.appendChild(table);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
container.appendChild(fragment);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function renderDnsTable(transportData) {
|
|
87
|
+
const dnsData = transportData['DNS'];
|
|
88
|
+
if (!dnsData) return;
|
|
89
|
+
const dnsRows = [
|
|
90
|
+
{ name: 'Transaction ID', value: dnsData['Transaction ID'] },
|
|
91
|
+
{
|
|
92
|
+
name: 'Type',
|
|
93
|
+
value: dnsData['Is Response'] ? 'Response' : 'Query',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: 'Query Names',
|
|
97
|
+
value: (dnsData['Query Names'] || []).join(', ') || '—',
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: 'Answer IPs',
|
|
101
|
+
value: (dnsData['Answer IPs'] || []).join(', ') || '—',
|
|
102
|
+
},
|
|
103
|
+
{ name: 'Questions', value: dnsData['Question Count'] },
|
|
104
|
+
{ name: 'Answers', value: dnsData['Answer Count'] },
|
|
105
|
+
];
|
|
106
|
+
createTable(dnsRows, ['DNS Field', 'Value'], 'sidedatatable');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function renderIcmpTable(protocol, transportData) {
|
|
110
|
+
if (protocol !== 'ICMP') return;
|
|
111
|
+
const icmpRows = [
|
|
112
|
+
{ name: 'Type', value: transportData['Type'] ?? '—' },
|
|
113
|
+
{ name: 'Code', value: transportData['Code'] ?? '—' },
|
|
114
|
+
{ name: 'ID', value: transportData['ID'] ?? '—' },
|
|
115
|
+
{ name: 'Sequence', value: transportData['Sequence'] ?? '—' },
|
|
116
|
+
];
|
|
117
|
+
createTable(icmpRows, ['ICMP Field', 'Value'], 'sidedatatable');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function renderSnmpTable(transportData) {
|
|
121
|
+
const snmpData = transportData['SNMP'];
|
|
122
|
+
if (!snmpData) return;
|
|
123
|
+
const snmpRows = [
|
|
124
|
+
{ name: 'Version', value: snmpData['Version'] || '—' },
|
|
125
|
+
{ name: 'Community', value: snmpData['Community'] || '—' },
|
|
126
|
+
{ name: 'PDU Type', value: snmpData['PDU Type'] || '—' },
|
|
127
|
+
];
|
|
128
|
+
createTable(snmpRows, ['SNMP Field', 'Value'], 'sidedatatable');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function renderDhcpTable(transportData) {
|
|
132
|
+
const dhcpData = transportData['DHCP'];
|
|
133
|
+
if (!dhcpData) return;
|
|
134
|
+
const dhcpRows = [
|
|
135
|
+
{ name: 'Message Type', value: dhcpData['Message Type'] || '—' },
|
|
136
|
+
{ name: 'Transaction ID', value: dhcpData['Transaction ID'] || '—' },
|
|
137
|
+
{ name: 'Client IP', value: dhcpData['Client IP'] || '—' },
|
|
138
|
+
{ name: 'Your IP', value: dhcpData['Your IP'] || '—' },
|
|
139
|
+
{ name: 'Server IP', value: dhcpData['Server IP'] || '—' },
|
|
140
|
+
];
|
|
141
|
+
createTable(dhcpRows, ['DHCP Field', 'Value'], 'sidedatatable');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function renderNtpTable(transportData) {
|
|
145
|
+
const ntpData = transportData['NTP'];
|
|
146
|
+
if (!ntpData) return;
|
|
147
|
+
const ntpRows = [
|
|
148
|
+
{ name: 'Version', value: ntpData['Version'] ?? '—' },
|
|
149
|
+
{ name: 'Mode', value: ntpData['Mode'] || '—' },
|
|
150
|
+
{ name: 'Stratum', value: ntpData['Stratum'] ?? '—' },
|
|
151
|
+
{ name: 'Reference ID', value: ntpData['Reference ID'] || '—' },
|
|
152
|
+
{ name: 'Leap Indicator', value: ntpData['Leap Indicator'] ?? '—' },
|
|
153
|
+
];
|
|
154
|
+
createTable(ntpRows, ['NTP Field', 'Value'], 'sidedatatable');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function renderSipTable(transportData) {
|
|
158
|
+
const sipData = transportData['SIP'];
|
|
159
|
+
if (!sipData) return;
|
|
160
|
+
const sipRows = [
|
|
161
|
+
{ name: 'Type', value: sipData['Type'] || '—' },
|
|
162
|
+
{
|
|
163
|
+
name: sipData['Type'] === 'Request' ? 'Method' : 'Status Code',
|
|
164
|
+
value: sipData['Method'] || sipData['Status Code'] || '—',
|
|
165
|
+
},
|
|
166
|
+
{ name: 'From', value: sipData['From'] || '—' },
|
|
167
|
+
{ name: 'To', value: sipData['To'] || '—' },
|
|
168
|
+
{ name: 'Call-ID', value: sipData['Call-ID'] || '—' },
|
|
169
|
+
];
|
|
170
|
+
createTable(sipRows, ['SIP Field', 'Value'], 'sidedatatable');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function renderHttpTable(transportData) {
|
|
174
|
+
const httpData = transportData['HTTP'];
|
|
175
|
+
if (!httpData) return;
|
|
176
|
+
const httpRows = [{ name: 'Type', value: httpData['Type'] || '—' }];
|
|
177
|
+
if (httpData['Type'] === 'Request') {
|
|
178
|
+
httpRows.push(
|
|
179
|
+
{ name: 'Method', value: httpData['Method'] || '—' },
|
|
180
|
+
{ name: 'URL', value: httpData['URL'] || '—' },
|
|
181
|
+
{ name: 'HTTP Version', value: httpData['HTTP Version'] || '—' },
|
|
182
|
+
{ name: 'Host', value: httpData['Host'] || '—' },
|
|
183
|
+
{ name: 'User-Agent', value: httpData['User-Agent'] || '—' },
|
|
184
|
+
{ name: 'Content-Type', value: httpData['Content-Type'] || '—' },
|
|
185
|
+
{ name: 'Content-Length', value: httpData['Content-Length'] || '—' },
|
|
186
|
+
{ name: 'Referer', value: httpData['Referer'] || '—' },
|
|
187
|
+
{ name: 'Accept', value: httpData['Accept'] || '—' },
|
|
188
|
+
{ name: 'Accept-Encoding', value: httpData['Accept-Encoding'] || '—' },
|
|
189
|
+
{ name: 'Connection', value: httpData['Connection'] || '—' },
|
|
190
|
+
);
|
|
191
|
+
} else {
|
|
192
|
+
httpRows.push(
|
|
193
|
+
{ name: 'Status Code', value: httpData['Status Code'] || '—' },
|
|
194
|
+
{ name: 'Status Message', value: httpData['Status Message'] || '—' },
|
|
195
|
+
{ name: 'HTTP Version', value: httpData['HTTP Version'] || '—' },
|
|
196
|
+
{ name: 'Server', value: httpData['Server'] || '—' },
|
|
197
|
+
{ name: 'Content-Type', value: httpData['Content-Type'] || '—' },
|
|
198
|
+
{ name: 'Content-Length', value: httpData['Content-Length'] || '—' },
|
|
199
|
+
{
|
|
200
|
+
name: 'Content-Encoding',
|
|
201
|
+
value: httpData['Content-Encoding'] || '—',
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
name: 'Transfer-Encoding',
|
|
205
|
+
value: httpData['Transfer-Encoding'] || '—',
|
|
206
|
+
},
|
|
207
|
+
{ name: 'Connection', value: httpData['Connection'] || '—' },
|
|
208
|
+
{ name: 'Location', value: httpData['Location'] || '—' },
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
createTable(httpRows, ['HTTP Field', 'Value'], 'sidedatatable');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function renderFtpTable(transportData) {
|
|
215
|
+
const ftpData = transportData['FTP'];
|
|
216
|
+
if (!ftpData) return;
|
|
217
|
+
const ftpRows = [{ name: 'Type', value: ftpData['Type'] || '—' }];
|
|
218
|
+
if (ftpData['Type'] === 'Command') {
|
|
219
|
+
ftpRows.push(
|
|
220
|
+
{ name: 'Command', value: ftpData['Command'] || '—' },
|
|
221
|
+
{ name: 'Argument', value: ftpData['Argument'] || '—' },
|
|
222
|
+
);
|
|
223
|
+
} else {
|
|
224
|
+
ftpRows.push(
|
|
225
|
+
{ name: 'Status Code', value: ftpData['Status Code'] || '—' },
|
|
226
|
+
{ name: 'Message', value: ftpData['Message'] || '—' },
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
createTable(ftpRows, ['FTP Field', 'Value'], 'sidedatatable');
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function renderSmtpTable(transportData) {
|
|
233
|
+
const smtpData = transportData['SMTP'];
|
|
234
|
+
if (!smtpData) return;
|
|
235
|
+
const smtpRows = [{ name: 'Type', value: smtpData['Type'] || '—' }];
|
|
236
|
+
if (smtpData['Type'] === 'Command') {
|
|
237
|
+
smtpRows.push(
|
|
238
|
+
{ name: 'Command', value: smtpData['Command'] || '—' },
|
|
239
|
+
{ name: 'Argument', value: smtpData['Argument'] || '—' },
|
|
240
|
+
);
|
|
241
|
+
} else {
|
|
242
|
+
smtpRows.push(
|
|
243
|
+
{ name: 'Status Code', value: smtpData['Status Code'] || '—' },
|
|
244
|
+
{ name: 'Message', value: smtpData['Message'] || '—' },
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
createTable(smtpRows, ['SMTP Field', 'Value'], 'sidedatatable');
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function renderPop3Table(transportData) {
|
|
251
|
+
const pop3Data = transportData['POP3'];
|
|
252
|
+
if (!pop3Data) return;
|
|
253
|
+
const pop3Rows = [{ name: 'Type', value: pop3Data['Type'] || '—' }];
|
|
254
|
+
if (pop3Data['Type'] === 'Command') {
|
|
255
|
+
pop3Rows.push(
|
|
256
|
+
{ name: 'Command', value: pop3Data['Command'] || '—' },
|
|
257
|
+
{ name: 'Argument', value: pop3Data['Argument'] || '—' },
|
|
258
|
+
);
|
|
259
|
+
} else {
|
|
260
|
+
pop3Rows.push(
|
|
261
|
+
{ name: 'Status', value: pop3Data['Status'] || '—' },
|
|
262
|
+
{ name: 'Message', value: pop3Data['Message'] || '—' },
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
createTable(pop3Rows, ['POP3 Field', 'Value'], 'sidedatatable');
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function renderImapTable(transportData) {
|
|
269
|
+
const imapData = transportData['IMAP'];
|
|
270
|
+
if (!imapData) return;
|
|
271
|
+
const imapRows = [{ name: 'Type', value: imapData['Type'] || '—' }];
|
|
272
|
+
if (imapData['Type'] === 'Command') {
|
|
273
|
+
imapRows.push(
|
|
274
|
+
{ name: 'Tag', value: imapData['Tag'] || '—' },
|
|
275
|
+
{ name: 'Command', value: imapData['Command'] || '—' },
|
|
276
|
+
{ name: 'Argument', value: imapData['Argument'] || '—' },
|
|
277
|
+
);
|
|
278
|
+
} else if (imapData['Type'] === 'Response') {
|
|
279
|
+
imapRows.push(
|
|
280
|
+
{ name: 'Tag', value: imapData['Tag'] || '—' },
|
|
281
|
+
{ name: 'Status', value: imapData['Status'] || '—' },
|
|
282
|
+
{ name: 'Message', value: imapData['Message'] || '—' },
|
|
283
|
+
);
|
|
284
|
+
} else {
|
|
285
|
+
imapRows.push(
|
|
286
|
+
{ name: 'Status', value: imapData['Status'] || '—' },
|
|
287
|
+
{ name: 'Info', value: imapData['Info'] || '—' },
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
createTable(imapRows, ['IMAP Field', 'Value'], 'sidedatatable');
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function renderTelnetTable(transportData) {
|
|
294
|
+
const telnetData = transportData['Telnet'];
|
|
295
|
+
if (!telnetData) return;
|
|
296
|
+
const negotiations = (telnetData['Negotiations'] || []).join(', ') || '—';
|
|
297
|
+
const telnetRows = [
|
|
298
|
+
{ name: 'Negotiations', value: negotiations },
|
|
299
|
+
{ name: 'Text', value: telnetData['Printable Text'] || '—' },
|
|
300
|
+
];
|
|
301
|
+
createTable(telnetRows, ['Telnet Field', 'Value'], 'sidedatatable');
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function renderIrcTable(transportData) {
|
|
305
|
+
const ircData = transportData['IRC'];
|
|
306
|
+
if (!ircData) return;
|
|
307
|
+
const ircRows = [
|
|
308
|
+
{ name: 'Command', value: ircData['Command'] || '—' },
|
|
309
|
+
{ name: 'Prefix', value: ircData['Prefix'] || '—' },
|
|
310
|
+
{ name: 'Parameters', value: ircData['Parameters'] || '—' },
|
|
311
|
+
{ name: 'Message Count', value: ircData['Message Count'] ?? '—' },
|
|
312
|
+
];
|
|
313
|
+
createTable(ircRows, ['IRC Field', 'Value'], 'sidedatatable');
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function renderMtpTable(transportData) {
|
|
317
|
+
const mtpData = transportData['MTP'];
|
|
318
|
+
if (!mtpData) return;
|
|
319
|
+
const mtpRows = [
|
|
320
|
+
{ name: 'Protocol', value: mtpData['Protocol'] || '—' },
|
|
321
|
+
{ name: 'Command', value: mtpData['Command'] || '—' },
|
|
322
|
+
{ name: 'Command ID', value: mtpData['Command ID'] || '—' },
|
|
323
|
+
{ name: 'Length', value: mtpData['Length'] ?? '—' },
|
|
324
|
+
];
|
|
325
|
+
createTable(mtpRows, ['MTP Field', 'Value'], 'sidedatatable');
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function renderLdapTable(transportData) {
|
|
329
|
+
const ldapData = transportData['LDAP'];
|
|
330
|
+
if (!ldapData) return;
|
|
331
|
+
const ldapRows = [
|
|
332
|
+
{ name: 'Message ID', value: ldapData['Message ID'] ?? '—' },
|
|
333
|
+
{ name: 'Operation', value: ldapData['Operation'] || '—' },
|
|
334
|
+
];
|
|
335
|
+
createTable(ldapRows, ['LDAP Field', 'Value'], 'sidedatatable');
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function renderMysqlTable(transportData) {
|
|
339
|
+
const mysqlData = transportData['MySQL'];
|
|
340
|
+
if (!mysqlData) return;
|
|
341
|
+
const mysqlRows = [
|
|
342
|
+
{ name: 'Type', value: mysqlData['Type'] || '—' },
|
|
343
|
+
{ name: 'Sequence', value: mysqlData['Sequence'] ?? '—' },
|
|
344
|
+
];
|
|
345
|
+
if (mysqlData['Type'] === 'Server Greeting') {
|
|
346
|
+
mysqlRows.push(
|
|
347
|
+
{ name: 'Protocol Version', value: mysqlData['Protocol Version'] ?? '—' },
|
|
348
|
+
{ name: 'Server Version', value: mysqlData['Server Version'] || '—' },
|
|
349
|
+
);
|
|
350
|
+
} else if (mysqlData['Type'] === 'Command') {
|
|
351
|
+
mysqlRows.push(
|
|
352
|
+
{ name: 'Command', value: mysqlData['Command'] || '—' },
|
|
353
|
+
{ name: 'Query', value: mysqlData['Query'] || '—' },
|
|
354
|
+
);
|
|
355
|
+
} else if (mysqlData['Type'] === 'Error') {
|
|
356
|
+
mysqlRows.push(
|
|
357
|
+
{ name: 'Error Code', value: mysqlData['Error Code'] ?? '—' },
|
|
358
|
+
{ name: 'Error Message', value: mysqlData['Error Message'] || '—' },
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
createTable(mysqlRows, ['MySQL Field', 'Value'], 'sidedatatable');
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function renderPostgresqlTable(transportData) {
|
|
365
|
+
const pgData = transportData['PostgreSQL'];
|
|
366
|
+
if (!pgData) return;
|
|
367
|
+
const pgRows = [
|
|
368
|
+
{ name: 'Type', value: pgData['Type'] || '—' },
|
|
369
|
+
{ name: 'Direction', value: pgData['Direction'] || '—' },
|
|
370
|
+
];
|
|
371
|
+
if (pgData['Protocol Version']) {
|
|
372
|
+
pgRows.push({ name: 'Protocol Version', value: pgData['Protocol Version'] });
|
|
373
|
+
}
|
|
374
|
+
if (pgData['Message Length'] !== undefined) {
|
|
375
|
+
pgRows.push({ name: 'Message Length', value: pgData['Message Length'] });
|
|
376
|
+
}
|
|
377
|
+
if (pgData['Body']) {
|
|
378
|
+
pgRows.push({ name: 'Body', value: pgData['Body'] });
|
|
379
|
+
}
|
|
380
|
+
createTable(pgRows, ['PostgreSQL Field', 'Value'], 'sidedatatable');
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function renderXmppTable(transportData) {
|
|
384
|
+
const xmppData = transportData['XMPP'];
|
|
385
|
+
if (!xmppData) return;
|
|
386
|
+
const xmppRows = [
|
|
387
|
+
{ name: 'Stanza Type', value: xmppData['Stanza Type'] || '—' },
|
|
388
|
+
{ name: 'From', value: xmppData['From'] || '—' },
|
|
389
|
+
{ name: 'To', value: xmppData['To'] || '—' },
|
|
390
|
+
];
|
|
391
|
+
createTable(xmppRows, ['XMPP Field', 'Value'], 'sidedatatable');
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function renderSmbTable(transportData) {
|
|
395
|
+
const smbData = transportData['SMB'];
|
|
396
|
+
if (!smbData) return;
|
|
397
|
+
const smbRows = [
|
|
398
|
+
{ name: 'Version', value: smbData['Version'] || '—' },
|
|
399
|
+
{ name: 'Command', value: smbData['Command'] || '—' },
|
|
400
|
+
{ name: 'Status', value: smbData['Status'] || '—' },
|
|
401
|
+
{ name: 'Is Response', value: smbData['Is Response'] ? 'Yes' : 'No' },
|
|
402
|
+
];
|
|
403
|
+
createTable(smbRows, ['SMB Field', 'Value'], 'sidedatatable');
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function renderMqttTable(transportData) {
|
|
407
|
+
const mqttData = transportData['MQTT'];
|
|
408
|
+
if (!mqttData) return;
|
|
409
|
+
const mqttRows = [
|
|
410
|
+
{ name: 'Message Type', value: mqttData['Message Type'] || '—' },
|
|
411
|
+
{ name: 'QoS', value: mqttData['QoS'] ?? '—' },
|
|
412
|
+
{ name: 'DUP Flag', value: mqttData['DUP Flag'] ? 'Yes' : 'No' },
|
|
413
|
+
{ name: 'Retain Flag', value: mqttData['Retain Flag'] ? 'Yes' : 'No' },
|
|
414
|
+
];
|
|
415
|
+
if (mqttData['Topic']) {
|
|
416
|
+
mqttRows.push({ name: 'Topic', value: mqttData['Topic'] });
|
|
417
|
+
}
|
|
418
|
+
createTable(mqttRows, ['MQTT Field', 'Value'], 'sidedatatable');
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function renderRtspTable(transportData) {
|
|
422
|
+
const rtspData = transportData['RTSP'];
|
|
423
|
+
if (!rtspData) return;
|
|
424
|
+
const rtspRows = [{ name: 'Type', value: rtspData['Type'] || '—' }];
|
|
425
|
+
if (rtspData['Type'] === 'Request') {
|
|
426
|
+
rtspRows.push(
|
|
427
|
+
{ name: 'Method', value: rtspData['Method'] || '—' },
|
|
428
|
+
{ name: 'URL', value: rtspData['URL'] || '—' },
|
|
429
|
+
{ name: 'RTSP Version', value: rtspData['RTSP Version'] || '—' },
|
|
430
|
+
{ name: 'CSeq', value: rtspData['CSeq'] || '—' },
|
|
431
|
+
{ name: 'Session', value: rtspData['Session'] || '—' },
|
|
432
|
+
{ name: 'Transport', value: rtspData['Transport'] || '—' },
|
|
433
|
+
);
|
|
434
|
+
} else {
|
|
435
|
+
rtspRows.push(
|
|
436
|
+
{ name: 'Status Code', value: rtspData['Status Code'] || '—' },
|
|
437
|
+
{ name: 'Status Message', value: rtspData['Status Message'] || '—' },
|
|
438
|
+
{ name: 'RTSP Version', value: rtspData['RTSP Version'] || '—' },
|
|
439
|
+
{ name: 'CSeq', value: rtspData['CSeq'] || '—' },
|
|
440
|
+
{ name: 'Content-Type', value: rtspData['Content-Type'] || '—' },
|
|
441
|
+
{ name: 'Content-Length', value: rtspData['Content-Length'] || '—' },
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
createTable(rtspRows, ['RTSP Field', 'Value'], 'sidedatatable');
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function renderTftpTable(transportData) {
|
|
448
|
+
const tftpData = transportData['TFTP'];
|
|
449
|
+
if (!tftpData) return;
|
|
450
|
+
const tftpRows = [{ name: 'Opcode', value: tftpData['Opcode'] || '—' }];
|
|
451
|
+
if (tftpData['Filename'] !== undefined) {
|
|
452
|
+
tftpRows.push(
|
|
453
|
+
{ name: 'Filename', value: tftpData['Filename'] || '—' },
|
|
454
|
+
{ name: 'Mode', value: tftpData['Mode'] || '—' },
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
if (tftpData['Block Number'] !== undefined) {
|
|
458
|
+
tftpRows.push({ name: 'Block Number', value: tftpData['Block Number'] });
|
|
459
|
+
}
|
|
460
|
+
if (tftpData['Data Length'] !== undefined) {
|
|
461
|
+
tftpRows.push({ name: 'Data Length', value: tftpData['Data Length'] });
|
|
462
|
+
}
|
|
463
|
+
if (tftpData['Error Code'] !== undefined) {
|
|
464
|
+
tftpRows.push(
|
|
465
|
+
{ name: 'Error Code', value: tftpData['Error Code'] },
|
|
466
|
+
{ name: 'Error Description', value: tftpData['Error Description'] || '—' },
|
|
467
|
+
{ name: 'Error Message', value: tftpData['Error Message'] || '—' },
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
createTable(tftpRows, ['TFTP Field', 'Value'], 'sidedatatable');
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
function renderBgpTable(transportData) {
|
|
474
|
+
const bgpData = transportData['BGP'];
|
|
475
|
+
if (!bgpData) return;
|
|
476
|
+
const bgpRows = [
|
|
477
|
+
{ name: 'Message Type', value: bgpData['Message Type'] || '—' },
|
|
478
|
+
{ name: 'Message Length', value: bgpData['Message Length'] ?? '—' },
|
|
479
|
+
];
|
|
480
|
+
if (bgpData['BGP Version'] !== undefined) {
|
|
481
|
+
bgpRows.push(
|
|
482
|
+
{ name: 'BGP Version', value: bgpData['BGP Version'] },
|
|
483
|
+
{ name: 'ASN', value: bgpData['ASN'] ?? '—' },
|
|
484
|
+
{ name: 'Hold Time', value: bgpData['Hold Time'] ?? '—' },
|
|
485
|
+
{ name: 'Router ID', value: bgpData['Router ID'] || '—' },
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
if (bgpData['Error Code'] !== undefined) {
|
|
489
|
+
bgpRows.push(
|
|
490
|
+
{ name: 'Error Name', value: bgpData['Error Name'] || '—' },
|
|
491
|
+
{ name: 'Error Code', value: bgpData['Error Code'] },
|
|
492
|
+
{ name: 'Error Subcode', value: bgpData['Error Subcode'] ?? '—' },
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
createTable(bgpRows, ['BGP Field', 'Value'], 'sidedatatable');
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
function renderHttp2Table(transportData) {
|
|
499
|
+
const http2Data = transportData['HTTP2'];
|
|
500
|
+
if (!http2Data) return;
|
|
501
|
+
const http2Rows = [
|
|
502
|
+
{ name: 'Frame Type', value: http2Data['Frame Type'] || '—' },
|
|
503
|
+
{
|
|
504
|
+
name: 'Connection Preface',
|
|
505
|
+
value: http2Data['Connection Preface'] ? 'Yes' : 'No',
|
|
506
|
+
},
|
|
507
|
+
];
|
|
508
|
+
if (http2Data['Frame Length'] !== undefined) {
|
|
509
|
+
http2Rows.push(
|
|
510
|
+
{ name: 'Frame Length', value: http2Data['Frame Length'] },
|
|
511
|
+
{ name: 'Frame Flags', value: http2Data['Frame Flags'] || '—' },
|
|
512
|
+
{ name: 'Stream ID', value: http2Data['Stream ID'] ?? '—' },
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
createTable(http2Rows, ['HTTP/2 Field', 'Value'], 'sidedatatable');
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
function renderNntpTable(transportData) {
|
|
519
|
+
const nntpData = transportData['NNTP'];
|
|
520
|
+
if (!nntpData) return;
|
|
521
|
+
const nntpRows = [{ name: 'Type', value: nntpData['Type'] || '—' }];
|
|
522
|
+
if (nntpData['Type'] === 'Command') {
|
|
523
|
+
nntpRows.push(
|
|
524
|
+
{ name: 'Command', value: nntpData['Command'] || '—' },
|
|
525
|
+
{ name: 'Argument', value: nntpData['Argument'] || '—' },
|
|
526
|
+
);
|
|
527
|
+
} else {
|
|
528
|
+
nntpRows.push(
|
|
529
|
+
{ name: 'Status Code', value: nntpData['Status Code'] || '—' },
|
|
530
|
+
{ name: 'Message', value: nntpData['Message'] || '—' },
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
createTable(nntpRows, ['NNTP Field', 'Value'], 'sidedatatable');
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function renderRadiusTable(transportData) {
|
|
537
|
+
const radiusData = transportData['RADIUS'];
|
|
538
|
+
if (!radiusData) return;
|
|
539
|
+
const radiusRows = [
|
|
540
|
+
{ name: 'Code', value: radiusData['Code'] || '—' },
|
|
541
|
+
{ name: 'Identifier', value: radiusData['Identifier'] ?? '—' },
|
|
542
|
+
{ name: 'Length', value: radiusData['Length'] ?? '—' },
|
|
543
|
+
];
|
|
544
|
+
const attrs = radiusData['Attributes'] || [];
|
|
545
|
+
attrs.forEach((attr) => {
|
|
546
|
+
radiusRows.push({ name: attr['Type'] || 'Attr', value: attr['Value'] || '—' });
|
|
547
|
+
});
|
|
548
|
+
createTable(radiusRows, ['RADIUS Field', 'Value'], 'sidedatatable');
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
module.exports = {
|
|
552
|
+
createTable,
|
|
553
|
+
renderDnsTable,
|
|
554
|
+
renderIcmpTable,
|
|
555
|
+
renderSnmpTable,
|
|
556
|
+
renderDhcpTable,
|
|
557
|
+
renderNtpTable,
|
|
558
|
+
renderSipTable,
|
|
559
|
+
renderHttpTable,
|
|
560
|
+
renderFtpTable,
|
|
561
|
+
renderSmtpTable,
|
|
562
|
+
renderPop3Table,
|
|
563
|
+
renderImapTable,
|
|
564
|
+
renderTelnetTable,
|
|
565
|
+
renderIrcTable,
|
|
566
|
+
renderMtpTable,
|
|
567
|
+
renderLdapTable,
|
|
568
|
+
renderMysqlTable,
|
|
569
|
+
renderPostgresqlTable,
|
|
570
|
+
renderXmppTable,
|
|
571
|
+
renderSmbTable,
|
|
572
|
+
renderMqttTable,
|
|
573
|
+
renderRtspTable,
|
|
574
|
+
renderTftpTable,
|
|
575
|
+
renderBgpTable,
|
|
576
|
+
renderHttp2Table,
|
|
577
|
+
renderNntpTable,
|
|
578
|
+
renderRadiusTable,
|
|
579
|
+
};
|