50 Commits

Author SHA1 Message Date
720fbbe75b Added example compose-file 2021-11-29 13:13:23 +01:00
a681bbd2d2 Removed sudo as container runs as root anyways 2021-11-29 13:11:11 +01:00
d9ee804c3b Removed src-references as hats the workdir 2021-11-29 13:10:44 +01:00
e320d8670b Add installation of package tcpdump 2021-11-29 13:10:05 +01:00
2d824543d1 fixed cmd 2021-11-29 13:09:49 +01:00
6e080907d1 Merge branch 'code-smell_handling' into dev 2021-11-29 09:58:04 +01:00
91c3aca9e2 Add function to get handshakeStage from keyInfo 2021-11-29 09:57:33 +01:00
31ab10c3e1 Fix wrong var-name 2021-11-29 09:57:05 +01:00
8ff7211f0f Revert "Extract packetType handling in own function"
This reverts commit 227ba127f8.
2021-11-29 09:50:14 +01:00
2ae85ababb Extract keyInfo reading to helper-file 2021-11-29 09:37:28 +01:00
227ba127f8 Extract packetType handling in own function 2021-11-29 09:36:21 +01:00
8417de5756 Extract checks with if-statements 2021-11-29 09:35:17 +01:00
54eadf3bc3 Fixed Regex codesmells 2021-11-29 09:24:18 +01:00
e39ebaac23 Fixed Regex codesmell 2021-11-29 09:23:08 +01:00
54d627d469 Fix typo 2021-11-29 09:20:38 +01:00
ca3c37be0f Activating strict-mode 2021-11-29 09:16:49 +01:00
96b52e63a0 Add exit-handler with error-detection 2021-11-29 09:16:39 +01:00
3c5e941cba Creating & Attaching streams / Error-logger 2021-11-29 09:15:49 +01:00
a468d7a57b Start tcpdump process 2021-11-29 09:14:50 +01:00
4ad5eba7e0 Change tag-srtting to recursive by field
This will properly set e.g. arrays
2021-11-26 21:03:11 +01:00
2646c9787e Changed key-checking to value-checking
This includes e.g. gettings, originally not included in keys
2021-11-26 21:00:15 +01:00
873f00b21b Remove deleting point and rename point to something useable 2021-11-26 19:17:43 +01:00
271554719e Remove wrong hint 2021-11-26 19:17:24 +01:00
e18de63d7c Revert "Move catch into then-onRejected to fix resolving then anyways."
This reverts commit 2356040572.
2021-11-26 19:14:01 +01:00
2356040572 Move catch into then-onRejected to fix resolving then anyways. 2021-11-26 19:07:27 +01:00
b0bbf0c71a Fixed wrong option-subname 2021-11-26 19:06:55 +01:00
37b78e7373 Fixed wrong logging-mode used 2021-11-26 18:54:09 +01:00
c5e1bb4c64 Added info-log "ok" 2021-11-26 18:37:55 +01:00
3c29ed2000 Implemented CheckWriteApi by writing and then deleting a TestPoint 2021-11-26 18:37:34 +01:00
ddf39b9433 Fixed require 2021-11-26 18:36:50 +01:00
3a927688d0 Changed fatal to error and added error handling to promise catch in main 2021-11-26 18:36:35 +01:00
c51cfc1b14 Fixed missing require 2021-11-26 18:35:51 +01:00
e1b2a7e016 Added influx checkBucket 2021-11-26 18:03:14 +01:00
fc5900b0ba Added influx checkHealth 2021-11-26 17:55:51 +01:00
354ca32a61 Merge branch 'dev' into f_influx-checks 2021-11-26 17:47:59 +01:00
d10e9bb2c6 Create influx-client 2021-11-26 17:43:42 +01:00
44cd3288cf Fixed stram not being in object-mode 2021-11-26 17:33:19 +01:00
3af4bb7cc6 Fixed wrong push 2021-11-26 17:33:07 +01:00
2a662e0bd1 Changed constructor to take influxDb 2021-11-26 17:32:31 +01:00
d7a9530b68 Cleaned up Promise 2021-11-26 17:31:31 +01:00
7de2250983 Added client-apis 2021-11-26 17:30:46 +01:00
bb3d843895 Fixed wrong joining 2021-11-25 18:42:45 +01:00
9472ed9198 Fix wrong usage of join()
Default splitter is ',' but we want nothing
2021-11-25 18:42:26 +01:00
dcd0ce8111 Added lib string-argv to extract bin and args from cmd 2021-11-25 18:32:43 +01:00
1a9ced0bb8 Changed exec to only wrap spawn 2021-11-25 18:32:07 +01:00
d77e3f8844 Fixed naming 2021-11-25 18:30:50 +01:00
e715cc1cac Removed unused env-vars for now 2021-11-25 13:59:45 +01:00
cf1b300f6a Changed documentation to remarks section 2021-11-25 03:14:24 +01:00
450f162cda Implemented InfluxPointWriter for writing into influx with stream 2021-11-25 03:13:05 +01:00
7ebcf573b9 Implemented stream to transform packets to datapoints 2021-11-25 02:54:43 +01:00
12 changed files with 369 additions and 44 deletions

View File

@@ -7,7 +7,11 @@ WORKDIR /usr/src/app
COPY package*.json ./ COPY package*.json ./
RUN npm install RUN npm install
RUN apt-get update
RUN apt-get -y install \
tcpdump
# Bundle app source # Bundle app source
COPY ./src/ . COPY ./src/ .
CMD ["npm", "run"] CMD ["npm", "run", "start"]

15
docker-compose.yml Normal file
View File

@@ -0,0 +1,15 @@
version: '3'
services:
rfmon:
container_name: rfmon
image: # TODO: Add image
restart: unless-stopped
network_mode: "host"
environment:
- LOGLEVEL=DEBUG
- WIFI_INTERFACE=wlan0
- INFLUX_URL=http://influxdb:8086/
- INFLUX_TOKEN=
- INFLUX_ORG=
- INFLUX_BUCKET=

31
package-lock.json generated
View File

@@ -10,8 +10,10 @@
"license": "AGPL-3.0", "license": "AGPL-3.0",
"dependencies": { "dependencies": {
"@influxdata/influxdb-client": "^1.20.0", "@influxdata/influxdb-client": "^1.20.0",
"@influxdata/influxdb-client-apis": "^1.20.0",
"log4js": "^6.3.0", "log4js": "^6.3.0",
"luxon": "^2.1.1" "luxon": "^2.1.1",
"string-argv": "^0.3.1"
} }
}, },
"node_modules/@influxdata/influxdb-client": { "node_modules/@influxdata/influxdb-client": {
@@ -19,6 +21,14 @@
"resolved": "https://registry.npmjs.org/@influxdata/influxdb-client/-/influxdb-client-1.20.0.tgz", "resolved": "https://registry.npmjs.org/@influxdata/influxdb-client/-/influxdb-client-1.20.0.tgz",
"integrity": "sha512-jaKSI63hmQ5VSkJrFJkYIXaKlhoF+mGd4HmOf7v/X7pmEi69ReHp922Wyx6/OeCrpndRMbsadk+XmGNdd43cFw==" "integrity": "sha512-jaKSI63hmQ5VSkJrFJkYIXaKlhoF+mGd4HmOf7v/X7pmEi69ReHp922Wyx6/OeCrpndRMbsadk+XmGNdd43cFw=="
}, },
"node_modules/@influxdata/influxdb-client-apis": {
"version": "1.20.0",
"resolved": "https://registry.npmjs.org/@influxdata/influxdb-client-apis/-/influxdb-client-apis-1.20.0.tgz",
"integrity": "sha512-KMTmXH4rbpS+NWGpqDjxcKTyan2rbiT2IM5AdRElKhH2sHbH96xwLgziaxeC+OCJLeNAdehJgae3I8WiZjbwdg==",
"peerDependencies": {
"@influxdata/influxdb-client": "*"
}
},
"node_modules/date-format": { "node_modules/date-format": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/date-format/-/date-format-3.0.0.tgz", "resolved": "https://registry.npmjs.org/date-format/-/date-format-3.0.0.tgz",
@@ -128,6 +138,14 @@
"node": ">=4.0" "node": ">=4.0"
} }
}, },
"node_modules/string-argv": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz",
"integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==",
"engines": {
"node": ">=0.6.19"
}
},
"node_modules/universalify": { "node_modules/universalify": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
@@ -143,6 +161,12 @@
"resolved": "https://registry.npmjs.org/@influxdata/influxdb-client/-/influxdb-client-1.20.0.tgz", "resolved": "https://registry.npmjs.org/@influxdata/influxdb-client/-/influxdb-client-1.20.0.tgz",
"integrity": "sha512-jaKSI63hmQ5VSkJrFJkYIXaKlhoF+mGd4HmOf7v/X7pmEi69ReHp922Wyx6/OeCrpndRMbsadk+XmGNdd43cFw==" "integrity": "sha512-jaKSI63hmQ5VSkJrFJkYIXaKlhoF+mGd4HmOf7v/X7pmEi69ReHp922Wyx6/OeCrpndRMbsadk+XmGNdd43cFw=="
}, },
"@influxdata/influxdb-client-apis": {
"version": "1.20.0",
"resolved": "https://registry.npmjs.org/@influxdata/influxdb-client-apis/-/influxdb-client-apis-1.20.0.tgz",
"integrity": "sha512-KMTmXH4rbpS+NWGpqDjxcKTyan2rbiT2IM5AdRElKhH2sHbH96xwLgziaxeC+OCJLeNAdehJgae3I8WiZjbwdg==",
"requires": {}
},
"date-format": { "date-format": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/date-format/-/date-format-3.0.0.tgz", "resolved": "https://registry.npmjs.org/date-format/-/date-format-3.0.0.tgz",
@@ -228,6 +252,11 @@
} }
} }
}, },
"string-argv": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz",
"integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg=="
},
"universalify": { "universalify": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",

View File

@@ -2,10 +2,10 @@
"name": "rfmon-to-influx", "name": "rfmon-to-influx",
"version": "1.0.0", "version": "1.0.0",
"description": "Writing (mostly meta-) data received in Wireless-Monitor-Mode into an InfluxDB", "description": "Writing (mostly meta-) data received in Wireless-Monitor-Mode into an InfluxDB",
"main": "src/main.js", "main": "main.js",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"start": "node src/main.js" "start": "node main.js"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -15,7 +15,9 @@
"license": "AGPL-3.0", "license": "AGPL-3.0",
"dependencies": { "dependencies": {
"@influxdata/influxdb-client": "^1.20.0", "@influxdata/influxdb-client": "^1.20.0",
"@influxdata/influxdb-client-apis": "^1.20.0",
"log4js": "^6.3.0", "log4js": "^6.3.0",
"luxon": "^2.1.1" "luxon": "^2.1.1",
"string-argv": "^0.3.1"
} }
} }

View File

@@ -1,20 +1,15 @@
const logger = require("./logger.js")("exec"); const logger = require("./logger.js")("exec");
const { spawn } = require("child_process"); const { spawn } = require("child_process");
const { parseArgsStringToArgv } = require('string-argv');
function exec(cmd, stdout, stderr, exit_handler){ function exec(cmd, options){
const [bin, ...args] = cmd.split(' ') const [bin, ...args] = parseArgsStringToArgv(cmd);
logger.addContext("binary", "bin"); logger.addContext("binary", "bin");
logger.debug(`Spawn process '${cmd}'`); logger.debug(`Spawn process '${cmd}'`);
let proc = spawn(bin, args); return spawn(bin, args, options);
return {
"process": proc,
"stdout": proc.stdout,
"stderr": proc.stderr
}
} }
// Specify exports // Specify exports

View File

@@ -0,0 +1,61 @@
const logger = require.main.require("./helper/logger.js")("influx-checks");
const Os = require("os");
const { InfluxDB, Point } = require('@influxdata/influxdb-client')
const Influx = require('@influxdata/influxdb-client-apis');
function checkHealth(influxDb){
return new Promise((resolve, reject) => {
new Influx.HealthAPI(influxDb) // Check influx health
.getHealth()
.catch((err) => {
logger.error("Could not communicate with Influx:");
logger.error(`Error [${err.code}]:`, err.message);
reject();
})
.then((res) => {
logger.debug("Server healthy.", "Version: ", res.version);
resolve(res);
});
});
}
function checkBucket(influxDb, options){
return new Promise((resolve, reject) => {
new Influx.BucketsAPI(influxDb).getBuckets(options)
.catch((err) => { // Weirdly the influx-Api returns 404 for searches of non-existing buckets
logger.error("Could not get bucket:");
logger.error(`Error [${err.code}]:`, err.message);
reject();
}).then((res) => { // But an empty list when the bucket exists, but token does not have permission to get details
logger.debug("Bucket found");
resolve(res);
// Now we know the bucket exists and we have some kind of permission.. but we still dont know if we are able to write to it..
});
});
}
function checkWriteApi(influxDb, options){
return new Promise((resolve, reject) => {
const writeApi = influxDb.getWriteApi(options.org, options.bucket); // Get WriteAPI
writeApi.writePoint(new Point("worker_connectionTest").tag("hostname", Os.hostname())) // Write point
writeApi.close()
.catch((err) => {
logger.error("Could not get writeApi:");
logger.error(`Error [${err.code}]:`, err.message);
reject();
}).then((res) => {
logger.debug("Writing ok");
resolve();
});
});
}
// Specify exports
module.exports = {
checkHealth,
checkBucket,
checkWriteApi,
};

View File

@@ -0,0 +1,43 @@
const { HandshakeStage } = require.main.require('./dto/Packet.js');
function keyInfoFromRaw(keyInfoRaw) {
return {
"KeyDescriptorVersion": keyInfoRaw>>0 & 0b111,
"KeyType": keyInfoRaw>>3 & 0b1,
"KeyIndex": keyInfoRaw>>4 & 0b11,
"Install": keyInfoRaw>>6 & 0b1,
"KeyACK": keyInfoRaw>>7 & 0b1,
"KeyMIC": keyInfoRaw>>8 & 0b1,
"Secure": keyInfoRaw>>9 & 0b1,
"Error": keyInfoRaw>>10 & 0b1,
"Request": keyInfoRaw>>11 & 0b1,
"EncryptedKeyData": keyInfoRaw>>12 & 0b1,
"SMKMessage": keyInfoRaw>>13 & 0b1,
};
}
const HANDSHAKE_STAGE_KEYINFO = {
"keys": ["Install", "KeyACK", "KeyMIC", "Secure"],
"0100": HandshakeStage[1],
"0010": HandshakeStage[2],
"1111": HandshakeStage[3],
"0011": HandshakeStage[4],
};
function handshakeStageFromKeyInfo(keyInfo){
// Extract compare-keys
let keyData = "";
for (const key of HANDSHAKE_STAGE_KEYINFO['keys']) {
keyData += keyInfo[key].toString();
}
// Get and return stage
return HANDSHAKE_STAGE_KEYINFO[keyData];
}
// Specify exports
module.exports = {
keyInfoFromRaw,
handshakeStageFromKeyInfo,
};

View File

@@ -1,7 +1,17 @@
"use strict";
const logger = require("./helper/logger.js")("main"); const logger = require("./helper/logger.js")("main");
const { requireEnvVars } = require("./helper/env.js"); const { requireEnvVars } = require("./helper/env.js");
const { exit } = require("process"); const { exit } = require("process");
const { exec } = require("./helper/exec.js");
const { InfluxDB } = require('@influxdata/influxdb-client');
const InfluxChecks = require('./helper/influx-checks.js');
const { RegexBlockStream } = require("./streamHandler/RegexBlockStream.js");
const { PacketStreamFactory } = require("./streamHandler/PacketStreamFactory.js");
const { PacketInfluxPointFactory } = require("./streamHandler/PacketInfluxPointFactory.js");
const { InfluxPointWriter } = require("./streamHandler/InfluxPointWriter.js");
/// Setup ENVs /// Setup ENVs
const env = process.env; const env = process.env;
@@ -9,8 +19,6 @@ const env = process.env;
{ {
env.LOGLEVEL ??= "INFO"; env.LOGLEVEL ??= "INFO";
env.WIFI_INTERFACE ??= "wlan0"; env.WIFI_INTERFACE ??= "wlan0";
env.WIFI_CHANNEL ??= [1,6,11];
env.WIFI_CHANNEL_TIME ??= 1;
} }
// Required vars // Required vars
let errorMsg = requireEnvVars([ let errorMsg = requireEnvVars([
@@ -22,3 +30,58 @@ if(errorMsg){
exit(1); exit(1);
} }
(async function() {
logger.info("Setup Influx..");
const influxDb = new InfluxDB({url: env.INFLUX_URL, token: env.INFLUX_TOKEN});
await InfluxChecks.checkHealth(influxDb)
.then((res) => {return InfluxChecks.checkBucket(influxDb, {
org: env.INFLUX_ORG,
name: env.INFLUX_BUCKET
})})
.then((res) => {return InfluxChecks.checkWriteApi(influxDb, {
org: env.INFLUX_ORG,
bucket: env.INFLUX_BUCKET
})})
.catch((err) => {
if(err) {
logger.error("Error whilst checking influx:");
logger.error(err);
}
logger.fatal("Setup influx failed!");
exit(1);
});
logger.info("Influx ok");
logger.info("Starting tcpdump..");
const TCPDUMP_BASECMD = "tcpdump -vvv -e -n -X -s0 -i"
let cmd = `${TCPDUMP_BASECMD} ${env.WIFI_INTERFACE}`;
let proc = exec(cmd);
logger.debug("Creating & Attaching streams..");
proc.stdout
.setEncoding("utf8")
.pipe(new RegexBlockStream(/^\d{2}:\d{2}:\d{2}.\d{6}.*(\n( {4,8}|\t\t?).*)+\n/gm))
.pipe(new PacketStreamFactory())
.pipe(new PacketInfluxPointFactory())
.pipe(new InfluxPointWriter(influxDb, env.INFLUX_ORG, env.INFLUX_BUCKET));
logger.debug("Attaching error-logger..");
proc.stderr.setEncoding("utf8").on("data", (data) => {
logger.error(data);
});
logger.debug("Attaching exit-handler..");
proc.on("exit", (code) => {
logger.info(`tcpdump exited code: ${code}`);
if (code) {
logger.fatal(`tcpdump exited with non-zero code: ${code}`);
exit(1);
}
logger.info("Shutdown");
exit(0);
});
logger.info("Startup complete");
})();

View File

@@ -0,0 +1,38 @@
const logger = require.main.require("./helper/logger.js")("InfluxPointWriter");
const { Writable } = require('stream');
const {InfluxDB, Point, HttpError} = require('@influxdata/influxdb-client')
/**
* Get points and write them into influx
*/
class InfluxPointWriter extends Writable{
/**
*
* @param {InfluxDB} influxDb InfluxDb
* @param {string} org Organization to use
* @param {string} bucket Bucket to use
* @param {Partial<WriteOptions>} options Options for WriteApi
*/
constructor(influxDb, org, bucket, options){
super({
objectMode: true
});
this._api = influxDb.getWriteApi(org, bucket, 'us', options);
}
_write(point, encoding, next){
this._api.writePoint(point);
next();
}
_flush(next){
this._api.flush(true)
.catch((err) => { next(new Error(`WriteApi rejected promise for flush: ${err}`)); })
.then(next);
}
}
// Specify exports
module.exports = {
InfluxPointWriter
};

View File

@@ -0,0 +1,84 @@
const logger = require.main.require("./helper/logger.js")("PacketStreamFactory");
const { Transform } = require('stream');
const {Point} = require('@influxdata/influxdb-client')
/** Keys to always use as tags */
const TAG_LIST = [
"srcMac",
"dstMac",
"bssid",
"frequency",
"flags",
];
/** Measurement-name and corresponding field-key */
const MEASUREMENT_MAP = new Map([
["Signal", "signal"],
["PayloadSize", "payloadSize"],
["DataRate", "dataRate"],
["SSID", "ssid"],
["AuthenticationType", "authenticationType"],
["AssociationSuccess", "associationIsSuccessful"],
["DisassociationReason", "disassociationReason"],
]);
/**
* Get packets and convert them into influx-points
*/
class PacketInfluxPointFactory extends Transform{
constructor(){
super({
readableObjectMode: true,
writableObjectMode: true
});
}
_transform(packet, encoding, next){
// Create measurements
MEASUREMENT_MAP.forEach((objKey, measurement) => {
if(packet[objKey] == null) return;
let point = new Point(measurement); // Create point
// Set tags
TAG_LIST.filter(tag => Object.keys(packet).includes(tag)) // Filter tags available on object
.filter(tag => packet[tag] != null) // Filter tags not falsy on object
.forEach(tag => {
tagObjectRecursively(point, tag, packet[tag]);
});
point.setField('value', packet[objKey]); // Set field
this.push(point); // Push point into stream
});
next(); // Get next packet
}
}
function tagObjectRecursively(point, tag, field, suffix = ""){
if(typeof(field) == "object"){
// TODO: Convert boolean-arrays like "packet.flags" to key: value
Object.entries(field).map(([key, value]) => {
tagObjectRecursively(point, tag, value, `_${key}${suffix}`);
});
}
else point.tag(tag+suffix, field);
}
/** Mapping for type -> field-method */
const POINT_FIELD_TYPE = new Map([
['boolean', function(key, value){ return this.booleanField(key, value); }],
['number', function(key, value){ return this.intField(key, value); }],
['string', function(key, value){ return this.stringField(key, value); }],
]);
Point.prototype.setField = function(key, value){
let setField = POINT_FIELD_TYPE.get(typeof value);
return setField.apply(this, [key, value]);
}
// Specify exports
module.exports = {
PacketInfluxPointFactory
};

View File

@@ -3,6 +3,7 @@ const { Transform } = require('stream');
const { DateTime } = require("luxon"); const { DateTime } = require("luxon");
const { PacketType, FlagType, Packet, PacketWithSSID, BeaconPacket, ProbeRequestPacket, ProbeResponsePacket, AuthenticationPacket, AuthenticationType, AssociationResponsePacket, DisassociationPacket, HandshakePacket, HandshakeStage } = require.main.require('./dto/Packet.js'); const { PacketType, FlagType, Packet, PacketWithSSID, BeaconPacket, ProbeRequestPacket, ProbeResponsePacket, AuthenticationPacket, AuthenticationType, AssociationResponsePacket, DisassociationPacket, HandshakePacket, HandshakeStage } = require.main.require('./dto/Packet.js');
const hexConv = require.main.require("./helper/hexConverter.js"); const hexConv = require.main.require("./helper/hexConverter.js");
const wifiStateAnalyser = require.main.require("./helper/wifiStateAnalyzer.js");
const PACKET_TYPE_MAP = { const PACKET_TYPE_MAP = {
"Beacon": PacketType.Beacon, "Beacon": PacketType.Beacon,
@@ -65,17 +66,22 @@ class PacketStreamFactory extends Transform{
?.forEach(match => packet.flags[FLAG_TYPE_MAP[match]] = true) // Set them to true in flags ?.forEach(match => packet.flags[FLAG_TYPE_MAP[match]] = true) // Set them to true in flags
); );
packet.dataRate = Number(data.match(/(?<=^|\s)[0-9]+(\.[0-9]+)?(?=\sMb\/?s($|\s))/i)?.[0]) || null; packet.dataRate = Number(data.match(/(?<=^|\s)\d+(\.\d+)?(?=\sMb\/?s($|\s))/i)?.[0]) || null;
packet.frequency = Number(data.match(/(?<=^|\s)[0-9]{4}(?=\sMHz($|\s))/i)?.[0]) || null; packet.frequency = Number(data.match(/(?<=^|\s)\d{4}(?=\sMHz($|\s))/i)?.[0]) || null;
packet.durationMicros = Number(data.match(/(?<=^|\s)[0-9]{1,4}(?=us($|\s))/i)?.[0]) || null; packet.durationMicros = Number(data.match(/(?<=^|\s)\d{1,4}(?=us($|\s))/i)?.[0]) || null;
packet.signal = Number(data.match(/(?<=^|\s)-[0-9]{2,3}(?=dBm\sSignal($|\s))/i)?.[0]) || null; packet.signal = Number(data.match(/(?<=^|\s)-\d{2,3}(?=dBm\sSignal($|\s))/i)?.[0]) || null;
let packetTypeStr = data.match(new RegExp('(?<=^|\\s)('+ PACKET_TYPES_REGEX +')(?=$|\\s)', 'i'))?.[0]; let packetTypeStr = data.match(new RegExp('(?<=^|\\s)('+ PACKET_TYPES_REGEX +')(?=$|\\s)', 'i'))?.[0];
packet.packetType = packetTypeStr? PACKET_TYPE_MAP[packetTypeStr]: if(packetTypeStr)
data.match(/(SA|TA|DA|RA|BSSID):.{17}\s*$/i)? PacketType.NoData: packet.packetType = PACKET_TYPE_MAP[packetTypeStr];
PacketType.Unknown; else if(data.match(/(SA|TA|DA|RA|BSSID):.{17}\s*$/i)){
packet.packetType = PacketType.NoData
}
else {
packet.packetType = PacketType.Unknown;
}
packet.srcMac = data.match(/(?<=(^|\s)(SA|TA):).{17}(?=$|\s)/i)?.[0] ?? null; packet.srcMac = data.match(/(?<=(^|\s)(SA|TA):).{17}(?=$|\s)/i)?.[0] ?? null;
@@ -129,25 +135,9 @@ class PacketStreamFactory extends Transform{
// Read key-information // Read key-information
const keyInfoRaw = (packet.payloadData[0x5]<<0x8) + packet.payloadData[0x6]; const keyInfoRaw = (packet.payloadData[0x5]<<0x8) + packet.payloadData[0x6];
const keyInfo = { const keyInfo = wifiStateAnalyser.keyInfoFromRaw(keyInfoRaw); // Convert
"KeyDescriptorVersion": keyInfoRaw>>0 & 0b111,
"KeyType": keyInfoRaw>>3 & 0b1,
"KeyIndex": keyInfoRaw>>4 & 0b11,
"Install": keyInfoRaw>>6 & 0b1,
"KeyACK": keyInfoRaw>>7 & 0b1,
"KeyMIC": keyInfoRaw>>8 & 0b1,
"Secure": keyInfoRaw>>9 & 0b1,
"Error": keyInfoRaw>>10 & 0b1,
"Request": keyInfoRaw>>11 & 0b1,
"EncryptedKeyData": keyInfoRaw>>12 & 0b1,
"SMKMessage": keyInfoRaw>>13 & 0b1,
};
newPacket.handshakeStage = (!keyInfo.Install && keyInfo.KeyACK && !keyInfo.KeyMIC && !keyInfo.Secure)? HandshakeStage[1] : newPacket.handshakeStage = wifiStateAnalyser.handshakeStageFromKeyInfo(keyInfo); // Get stage
(!keyInfo.Install && !keyInfo.KeyACK && keyInfo.KeyMIC && !keyInfo.Secure)? HandshakeStage[2] :
( keyInfo.Install && keyInfo.KeyACK && keyInfo.KeyMIC && keyInfo.Secure)? HandshakeStage[3] :
(!keyInfo.Install && !keyInfo.KeyACK && keyInfo.KeyMIC && keyInfo.Secure)? HandshakeStage[4] :
null;
break; break;
} }
if(newPacket) packet = Object.assign(newPacket, packet); if(newPacket) packet = Object.assign(newPacket, packet);

View File

@@ -10,9 +10,10 @@ class RegexBlockStream extends Transform{
matchAllOnFlush; matchAllOnFlush;
/** /**
* @param {RegExp} matcher Block-match - WARNING: It should match a clean-block (including e.g. newline)! Otherwise buffer will get dirty and use more and more ressources. * @param {RegExp} matcher Block-match
* @param {boolean} withholdLastBlock When true, the last matches block will not be submitted to prevent submitting incomplete blocks. * @param {boolean} withholdLastBlock When true, the last matches block will not be submitted to prevent submitting incomplete blocks.
* @param {boolean} matchAllOnFlush (Only in combination with withholdLastBlock) When enabled, the buffer will be matched on last time on _flush (stream deconstruction) and write any, also incomplete, blocks * @param {boolean} matchAllOnFlush (Only in combination with withholdLastBlock) When enabled, the buffer will be matched on last time on _flush (stream deconstruction) and write any, also incomplete, blocks
* @remarks WARNING: It should match a clean-block (including e.g. newline)! Otherwise buffer will get dirty and use more and more resources.
*/ */
constructor(matcher, withholdLastBlock = true, matchAllOnFlush = false){ constructor(matcher, withholdLastBlock = true, matchAllOnFlush = false){
super({ super({
@@ -26,7 +27,7 @@ class RegexBlockStream extends Transform{
} }
_transform(chunk, encoding, next){ _transform(chunk, encoding, next){
chunk = this.readableBuffer.length? this.readableBuffer.join() + chunk: chunk; // Add previous buffer to current chunk chunk = this.readableBuffer.length? this.readableBuffer.join('') + chunk: chunk; // Add previous buffer to current chunk
this.readableBuffer.length && this.readableBuffer.clear(); // Clear buffer once we read it this.readableBuffer.length && this.readableBuffer.clear(); // Clear buffer once we read it
let matches = chunk.match(this.matcher); // Match let matches = chunk.match(this.matcher); // Match
@@ -51,7 +52,7 @@ class RegexBlockStream extends Transform{
_flush(next){ _flush(next){
if(matchAllOnFlush){ // When requested, we'll match one last time over the remaining buffer if(matchAllOnFlush){ // When requested, we'll match one last time over the remaining buffer
let chunk = this.readableBuffer.toString(); let chunk = this.readableBuffer.join('');
let matches = chunk.match(this.matcher); // Match remaining buffer let matches = chunk.match(this.matcher); // Match remaining buffer
_writeMatches(matches); // Write matches including last element _writeMatches(matches); // Write matches including last element
} }