Compare commits
14 Commits
3c3ab18410
...
d0ee1a7044
Author | SHA1 | Date | |
---|---|---|---|
d0ee1a7044 | |||
57394882cc | |||
b41d728ba9 | |||
d6135a02e9 | |||
ffe14e3f53 | |||
09bea81058 | |||
66c0fdfe12 | |||
b32b5cbed7 | |||
e86b5fca9a | |||
d2178f3b73 | |||
fe5dec7860 | |||
0d472e8cb3 | |||
bba5da2599 | |||
c2210dfb59 |
@ -9,11 +9,17 @@ const PacketType = {
|
||||
Acknowledgment: 'Acknowledgment',
|
||||
BlockAcknowledgment: 'BlockAcknowledgment',
|
||||
NoData: 'NoData',
|
||||
Authentication: 'Authentication',
|
||||
AssociationRequest: 'AssociationRequest',
|
||||
AssociationResponse: 'AssociationResponse',
|
||||
Disassociation: 'Disassociation',
|
||||
Handshake: 'Handshake',
|
||||
Unknown: 'Unknown'
|
||||
}
|
||||
|
||||
class Packet{
|
||||
timestampMicros;
|
||||
isRetry;
|
||||
|
||||
srcMac;
|
||||
dstMac;
|
||||
@ -23,9 +29,11 @@ class Packet{
|
||||
frequency;
|
||||
dataRate;
|
||||
|
||||
durationMicros;
|
||||
|
||||
payloadData;
|
||||
get payloadSize(){
|
||||
return payloadData.length/2;
|
||||
return this.payloadData.length;
|
||||
}
|
||||
|
||||
packetType;
|
||||
@ -40,6 +48,34 @@ class BeaconPacket extends PacketWithSSID{}
|
||||
class ProbeRequestPacket extends PacketWithSSID{}
|
||||
class ProbeResponsePacket extends PacketWithSSID{}
|
||||
|
||||
const AuthenticationType = {
|
||||
OpenSystem_1: 'OpenSystem_1',
|
||||
OpenSystem_2: 'OpenSystem_2',
|
||||
Unknown: 'Unknown',
|
||||
}
|
||||
class AuthenticationPacket extends Packet{
|
||||
authenticationType;
|
||||
}
|
||||
|
||||
class AssociationRequestPacket extends PacketWithSSID{}
|
||||
class AssociationResponsePacket extends Packet{
|
||||
associationIsSuccessful;
|
||||
}
|
||||
|
||||
class DisassociationPacket extends Packet{
|
||||
disassociationReason;
|
||||
}
|
||||
|
||||
|
||||
const HandshakeStage = {
|
||||
1: '1',
|
||||
2: '2',
|
||||
3: '3',
|
||||
4: '4'
|
||||
}
|
||||
class HandshakePacket extends Packet{
|
||||
handshakeStage;
|
||||
}
|
||||
|
||||
// Specify exports
|
||||
module.exports = {
|
||||
@ -48,5 +84,12 @@ module.exports = {
|
||||
PacketWithSSID,
|
||||
BeaconPacket,
|
||||
ProbeRequestPacket,
|
||||
ProbeResponsePacket
|
||||
ProbeResponsePacket,
|
||||
AuthenticationType,
|
||||
AuthenticationPacket,
|
||||
AssociationRequestPacket,
|
||||
AssociationResponsePacket,
|
||||
DisassociationPacket,
|
||||
HandshakeStage,
|
||||
HandshakePacket,
|
||||
};
|
||||
|
24
src/helper/hexConverter.js
Normal file
24
src/helper/hexConverter.js
Normal file
@ -0,0 +1,24 @@
|
||||
// From https://stackoverflow.com/a/34356351
|
||||
|
||||
// Convert a hex string to a byte array
|
||||
function hexToBytes(hex) {
|
||||
for (var bytes = [], c = 0; c < hex.length; c += 2)
|
||||
bytes.push(parseInt(hex.substr(c, 2), 16));
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// Convert a byte array to a hex string
|
||||
function bytesToHex(bytes) {
|
||||
for (var hex = [], i = 0; i < bytes.length; i++) {
|
||||
var current = bytes[i] < 0 ? bytes[i] + 256 : bytes[i];
|
||||
hex.push((current >>> 4).toString(16));
|
||||
hex.push((current & 0xF).toString(16));
|
||||
}
|
||||
return hex.join("");
|
||||
}
|
||||
|
||||
// Specify exports
|
||||
module.exports = {
|
||||
hexToBytes,
|
||||
bytesToHex
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
const logger = require.main.require("./helper/logger.js")("PacketStreamFactory");
|
||||
const { Transform } = require('stream');
|
||||
const { DateTime } = require("luxon");
|
||||
const { PacketType, Packet, PacketWithSSID, BeaconPacket, ProbeRequestPacket, ProbeResponsePacket } = require.main.require('./dto/Packet.js');
|
||||
const { PacketType, 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 PACKET_TYPE_MAP = {
|
||||
"Beacon": PacketType.Beacon,
|
||||
@ -12,10 +13,20 @@ const PACKET_TYPE_MAP = {
|
||||
"Request-To-Send": PacketType.RequestToSend,
|
||||
"Clear-To-Send": PacketType.ClearToSend,
|
||||
"Acknowledgment": PacketType.Acknowledgment,
|
||||
"BA": PacketType.BlockAcknowledgment
|
||||
"BA": PacketType.BlockAcknowledgment,
|
||||
"Authentication": PacketType.Authentication,
|
||||
"Assoc Request": PacketType.AssociationRequest,
|
||||
"Assoc Response": PacketType.AssociationResponse,
|
||||
"Disassociation:": PacketType.Disassociation,
|
||||
"EAPOL": PacketType.Handshake,
|
||||
};
|
||||
const PACKET_TYPES_REGEX = Object.keys(PACKET_TYPE_MAP).join('|');
|
||||
|
||||
const AUTHENTICATION_TYPE_MAP = {
|
||||
"(Open System)-1": AuthenticationType.OpenSystem_1,
|
||||
"(Open System)-2": AuthenticationType.OpenSystem_2,
|
||||
}
|
||||
|
||||
/**
|
||||
* Read data from text-blocks and convert them to Packet
|
||||
*/
|
||||
@ -36,8 +47,8 @@ class PacketStreamFactory extends Transform{
|
||||
|
||||
const lines = chunk.split('\n');
|
||||
const header = lines.splice(0, 1)[0]; // Grab first line, 'lines' is now the payload
|
||||
this._handleHeader(packet, header);
|
||||
this._handlePayload(packet, lines);
|
||||
packet = this._handleHeader(packet, header);
|
||||
packet = this._handlePayload(packet, lines);
|
||||
|
||||
logger.debug(packet);
|
||||
|
||||
@ -48,34 +59,93 @@ class PacketStreamFactory extends Transform{
|
||||
// Convert time to epoch-micros Unfortunately luxon doesnt use micros, but millis as smallest time-unit requiring some "hacks"
|
||||
packet.timestampMicros = DateTime.fromISO(data.slice(0, 12)).toSeconds() + data.slice(12, 15)/1000000;
|
||||
|
||||
packet.dataRate = Number(data.match(/(^| )([0-9]+(\.[0-9]+)?) Mb\/s($| )/i)?.[2]) || null;
|
||||
packet.frequency = Number(data.match(/(^| )([0-9]{4}) MHz($| )/i)?.[2]) || null;
|
||||
packet.isRetry = data.match(/(?<=^|\s)Retry(?=$|\s)/i)? true: false;
|
||||
|
||||
packet.signal = Number(data.match(/(^| )(-[0-9]{2})dBm Signal($| )/i)?.[2]) || null;
|
||||
packet.dataRate = Number(data.match(/(?<=^|\s)[0-9]+(\.[0-9]+)?(?=\sMb\/?s($|\s))/i)?.[0]) || null;
|
||||
packet.frequency = Number(data.match(/(?<=^|\s)[0-9]{4}(?=\sMHz($|\s))/i)?.[0]) || null;
|
||||
|
||||
let packetTypeStr = data.match(new RegExp(`(^|.{80} )(${PACKET_TYPES_REGEX})($| )`, 'i'))?.[2];
|
||||
packet.durationMicros = Number(data.match(/(?<=^|\s)[0-9]{1,4}(?=us($|\s))/i)?.[0]) || null;
|
||||
|
||||
packet.signal = Number(data.match(/(?<=^|\s)-[0-9]{2,3}(?=dBm\sSignal($|\s))/i)?.[0]) || null;
|
||||
|
||||
let packetTypeStr = data.match(new RegExp('(?<=^|\\s)('+ PACKET_TYPES_REGEX +')(?=$|\\s)', 'i'))?.[0];
|
||||
packet.packetType = packetTypeStr? PACKET_TYPE_MAP[packetTypeStr]: PacketType.Unknown;
|
||||
|
||||
packet.srcMac = data.match(/(^| )(SA|TA):(.{17})($| )/i)?.[3] ?? null;
|
||||
packet.srcMac = data.match(/(?<=(^|\s)(SA|TA):).{17}(?=$|\s)/i)?.[0] ?? null;
|
||||
|
||||
packet.dstMac = data.match(/(^| )(DA|RA):(.{17})($| )/i)?.[3] ?? null;
|
||||
packet.dstMac = data.match(/(?<=(^|\s)(DA|RA):).{17}(?=$|\s)/i)?.[0] ?? null;
|
||||
|
||||
packet.bssid = data.match(/(^| )BSSID:(.{17})($| )/i)?.[2] ?? null;
|
||||
packet.bssid = data.match(/(?<=(^|\s)BSSID:).{17}(?=$|\s)/i)?.[0] ?? null;
|
||||
|
||||
// Cover special cases with more data
|
||||
let newPacket;
|
||||
switch(packet.packetType){
|
||||
case PacketType.Beacon:
|
||||
case PacketType.ProbeRequest:
|
||||
case PacketType.ProbeResponse:
|
||||
packet = Object.assign(new PacketWithSSID(), packet); // Create new, more specific, packet and copy old data over
|
||||
packet.ssid = data.match(new RegExp(`(^| )${packetTypeStr} `+'\\'+`((.{0,32})`+'\\'+`)($| )`, 'i'))?.[2] ?? null;
|
||||
case PacketType.AssociationRequest:
|
||||
newPacket = new PacketWithSSID();
|
||||
newPacket.ssid = data.match(new RegExp('(?<=(^|\\s)'+ packetTypeStr +'\\s\\().{0,32}(?=\\)($|\\s))', 'i'))?.[0] ?? null;
|
||||
break;
|
||||
|
||||
case PacketType.Authentication:
|
||||
newPacket = new AuthenticationPacket();
|
||||
newPacket.authenticationType = AUTHENTICATION_TYPE_MAP[data.match(/(?<=(^|\s)Authentication\s).{3,}(?=\:(\s|$))/i)[0]] ?? AuthenticationType.Unknown;
|
||||
break;
|
||||
|
||||
case PacketType.AssociationResponse:
|
||||
newPacket = new AssociationResponsePacket();
|
||||
newPacket.associationIsSuccessful = data.match(/(?<=(^|\s)Assoc\sResponse\s.{0,30})Successful(?=\s|$)/i) ? true : false;
|
||||
break;
|
||||
|
||||
case PacketType.Disassociation:
|
||||
newPacket = new DisassociationPacket();
|
||||
newPacket.disassociationReason = data.match(/(?<=(^|\s)Disassociation:\s).*$/i)?.[0] ?? null;
|
||||
break;
|
||||
}
|
||||
if(newPacket) packet = Object.assign(newPacket, packet); // Use new, more specific, packet and copy old data over
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
_handlePayload(packet, data){
|
||||
data = data.join('');
|
||||
|
||||
// Get payload-Hex-Data. If there is no data: empty
|
||||
packet.payloadData = data.join('').match(/(?<=\s)([A-F0-9]{1,4}(?!(\.|x)))/igm)?.join('') ?? '';
|
||||
packet.payloadData = hexConv.hexToBytes(data.match(/(?<=\s)([A-F0-9]{1,4}(?!(\.|x)))/igm)?.join('') ?? '');
|
||||
|
||||
// Cover special cases with more data
|
||||
let newPacket;
|
||||
switch(packet.packetType){
|
||||
case PacketType.Handshake:
|
||||
newPacket = new HandshakePacket();
|
||||
|
||||
// Read key-information
|
||||
let keyInfoRaw = (packet.payloadData[0x5]<<0x8) + packet.payloadData[0x6];
|
||||
let keyInfo = {
|
||||
"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] :
|
||||
(!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;
|
||||
}
|
||||
if(newPacket) packet = Object.assign(newPacket, packet);
|
||||
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user