UNPKG

n8n-nodes-tshark

Version:
206 lines 9.11 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TsharkTrigger = void 0; const child_process_1 = require("child_process"); const ShellUtils_1 = require("./utils/ShellUtils"); const TsharkUtils_1 = require("./utils/TsharkUtils"); class TsharkTrigger { constructor() { this.description = { displayName: 'Tshark Trigger', name: 'tsharkTrigger', icon: 'file:TsharkTriggerLogo.svg', group: ['trigger'], version: 1, triggerPanel: true, subtitle: '={{$parameter["operation"]}}', description: 'Starts the workflow with Tshark', defaults: { name: 'Tshark Trigger', }, inputs: ["main"], outputs: ["main"], credentials: [ { displayName: 'Local Sudo Password', name: 'onlyPassword', required: true, }, ], properties: [ { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, options: [ { name: 'Sniff Beacon', value: 'beacon', description: 'Trigger when a beacon frames is detected', action: 'Sniff beacon frames', }, { name: 'Sniff Probe Response', value: 'probe_response', description: 'Trigger when a probe responses is detected', action: 'Sniff probe responses', }, { name: 'Sniff Probe Request', value: 'probe_request', description: 'Trigger when a probe requests is detected', action: 'Sniff probe requests', }, ], default: 'beacon', }, { displayName: 'Interface', name: 'network_interface', type: 'string', default: 'wlan1', description: 'Use this network monitoring interface', required: true, }, { displayName: 'Channel Hopping List', name: 'channels', type: 'string', default: '1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48', description: 'List of channels to hop through (check supported channels with "iw list")', required: true, }, { displayName: 'Channel Hopping Interval', name: 'hopping_interval', type: 'number', default: 30, description: 'Interval between channel hops (in seconds)', required: true, }, { displayName: 'Emission Interval', name: 'limit_interval', type: 'number', default: 60, description: 'Interval between trigger emissions (in seconds)', required: true, }, { displayName: 'Maximum Emissions', name: 'limit_emits', type: 'number', default: 10, description: 'Maximum number of trigger emissions per interval', required: true, }, ], }; } async trigger() { const operation = this.getNodeParameter('operation', 0); const network_interface = this.getNodeParameter('network_interface', 0); const limit_emits = this.getNodeParameter('limit_emits', 0); const limit_interval = this.getNodeParameter('limit_interval', 0); const credentials = await this.getCredentials('onlyPassword'); let command = `tshark -help`; if (operation === 'beacon') { command = `tshark -i ${network_interface} -Y "wlan.fc.type_subtype == 8 && wlan.ssid != \\"\\"" -T fields -e wlan.fc.type_subtype -e wlan.sa -e wlan.sa_resolved -e wlan.ssid -e radiotap.channel.freq -e radiotap.dbm_antsignal -N m -l`; } else if (operation === 'probe_response') { command = `tshark -i ${network_interface} -Y "wlan.fc.type_subtype == 5 && wlan.ssid != \\"\\"" -T fields -e wlan.fc.type_subtype -e wlan.sa -e wlan.sa_resolved -e wlan.ssid -e radiotap.channel.freq -e radiotap.dbm_antsignal -N m -l`; } else if (operation === 'probe_request') { command = `tshark -i ${network_interface} -Y "wlan.fc.type_subtype == 4 && wlan.ssid != \\"\\"" -T fields -e wlan.fc.type_subtype -e wlan.sa -e wlan.sa_resolved -e wlan.ssid -e radiotap.channel.freq -e radiotap.dbm_antsignal -N m -l`; } const shellUtils = new ShellUtils_1.ShellUtils(); const workingDirectory = await shellUtils.resolveHomeFolder('~/'); console.log(`Tshark process starting ${command}`); let child = (0, child_process_1.spawn)('sudo', ['-S', '-k', '-p', 'pwd:', 'sh', '-c', command], { cwd: workingDirectory, detached: true, }); child.stderr.pipe(process.stderr); child.stderr.on('data', (error) => { if (error.toString() == 'pwd:') { child.stdin.write(credentials.password + '\n'); } }); let limit_count = 0; let previous = ''; let results = []; child.stdout.on('data', (data) => { const lines = data .toString() .split('\n') .filter((line) => line.trim() !== ''); for (const line of lines) { if (line !== previous) { const fields = line.split(/\s+/); if (fields.length == 6) { const frameType = fields[0]; const macAddress = fields[1]; const macResolved = fields[2]; const ssid = TsharkUtils_1.TsharkUtils.decodeSSID(fields[3]); const frequencyMHz = fields[4]; const signalDbm = fields[5]; limit_count++; if (ssid.length > 0 && results.length < limit_emits) { results.push({ frameType, macAddress, macResolved, ssid, frequencyMHz, signalDbm }); } else { const r = Math.floor(Math.random() * limit_count); if (r < limit_emits) { results[r] = { frameType, macAddress, macResolved, ssid, frequencyMHz, signalDbm }; } } } previous = line; } } }); const resetLimit = () => { if (results.length > 0) { this.emit([this.helpers.returnJsonArray(results)]); } results = []; limit_count = 0; }; const limit = setInterval(resetLimit, limit_interval * 1000); child.on('close', (code, signal) => { console.log(`Tshark process terminated`); }); const channelsParam = this.getNodeParameter('channels', 0); const hopping_interval = this.getNodeParameter('hopping_interval', 0); const channels = channelsParam.split(',').map((c) => c.trim()); let currentChannelIndex = 0; async function channelHop() { const channel = channels[currentChannelIndex]; const cmdHopping = `iw dev ${network_interface} set channel ${channel}`; await shellUtils .sudoCommand(cmdHopping, workingDirectory, credentials.password) .then((output) => { console.log(`Channel hopping done ${cmdHopping}`); }); currentChannelIndex = (currentChannelIndex + 1) % channels.length; } const timer = setInterval(channelHop, hopping_interval * 1000); async function closeFunction() { clearInterval(limit); clearInterval(timer); console.log(`Child process : ${child.pid}`); if (child.pid) { process.kill(-child.pid, 'SIGKILL'); } else { child.kill('SIGKILL'); } } return { closeFunction, }; } } exports.TsharkTrigger = TsharkTrigger; //# sourceMappingURL=TsharkTrigger.node.js.map