node-win-pcap
Version:
Node.js binding for windows packet sniffing
92 lines (79 loc) • 2.62 kB
JavaScript
const EventEmitter = require('node:events')
const os = require('node:os')
const path = require('node:path')
const addonPath = require('@mapbox/node-pre-gyp').find(path.resolve(path.join(__dirname, '..', 'package.json')))
const addon = require(addonPath)
class NodeWinPcap extends EventEmitter {
static Protocol = {
TCP: 6,
UDP: 17,
};
static GetLocalAddress() {
const interfaces = os.networkInterfaces()
for (const iface of Object.values(interfaces)) {
for (const address of iface) {
if (address.family === 'IPv4' && !address.internal) {
return address.address
}
}
}
throw new Error('No local IPv4 address found.')
}
constructor(ipAddress = NodeWinPcap.GetLocalAddress(), options = {}) {
super()
this.socket = null
this.isListening = false
this.ipAddress = ipAddress
this.socketSize = options.socketSize || 65536 * 4 // 256KB default
this.source_ip_filter = ''
this.dest_ip_filter = ''
}
start(source_ip_filter = '', dest_ip_filter = '') {
if (this.isListening) {
throw new Error('Already listening')
}
if (!this.ipAddress) {
throw new Error('IP address must be provided in the constructor.')
}
this.source_ip_filter = source_ip_filter
this.dest_ip_filter = dest_ip_filter
try {
// Pass the definite socketSize to the addon
this.socket = addon.createNodeWinPcap(this.ipAddress, this.socketSize)
this.isListening = true
this._listen()
} catch (error) {
throw new Error(`Failed to start sniffer: ${error.message}. Make sure to run as root.`)
}
}
stop() {
if (!this.isListening) return
this.isListening = false
if (this.socket !== null) {
addon.closeSocket(this.socket)
this.socket = null
}
}
_listen() {
if (!this.isListening) return
setImmediate(() => {
try {
// Pass filters to the C++ addon
const packet = addon.receivePacket(this.socket, this.source_ip_filter, this.dest_ip_filter)
// Only emit if a packet is returned (C++ will handle filtering)
if (packet) {
// The C++ addon will now return the parsed IP header as part of the packet
this.emit('packet', packet)
}
this._listen() // Continue listening
} catch (error) {
// Errors might occur (e.g., non-IP packets), so we can choose to ignore or emit.
// For now, we'll continue to emit them.
this.emit('error', error)
}
})
}
}
module.exports = {
NodeWinPcap
}