haraka-plugin-p0f
Advanced tools
Comparing version 1.0.1 to 1.0.2
# 1.0.1 - 2017-09-01 | ||
## 1.0.1 - 2017-09-11 | ||
- when socket_path is not configured, emit an error | ||
## 1.0.1 - 2017-09-01 | ||
- repackaged as p0f, added contrib scripts, test release | ||
# 1.0.0 - 2017-07-27 | ||
## 1.0.0 - 2017-07-27 | ||
- import from Haraka |
93
index.js
'use strict'; | ||
// p0f v3 client - http://lcamtuf.coredump.cx/p0f3/ | ||
var net = require('net'); | ||
var ipaddr = require('ipaddr.js'); | ||
const net = require('net'); | ||
const ipaddr = require('ipaddr.js'); | ||
function P0FClient (path) { | ||
var self = this; | ||
const self = this; | ||
@@ -18,3 +18,3 @@ this.sock = null; | ||
var connect = function () { | ||
function connect () { | ||
self.sock = net.createConnection(path); | ||
@@ -33,3 +33,3 @@ self.sock.setTimeout(5 * 1000); | ||
self.sock.on('data', function (data) { | ||
for (var i=0; i<data.length/232; i++) { | ||
for (let i=0; i<data.length/232; i++) { | ||
self.decode_response(data.slice(((i) ? 232*i : 0), 232*(i+1))); | ||
@@ -56,4 +56,4 @@ } | ||
// Clear the receive queue | ||
for (var i=0; i<self.receive_queue.length; i++) { | ||
var item = self.receive_queue.shift(); | ||
for (let i=0; i<self.receive_queue.length; i++) { | ||
const item = self.receive_queue.shift(); | ||
item.cb(self.socket_has_error); | ||
@@ -64,3 +64,3 @@ continue; | ||
}); | ||
}; | ||
} | ||
connect(); | ||
@@ -76,6 +76,7 @@ } | ||
P0FClient.prototype.decode_response = function (data) { | ||
var decode_string = function (data2, start, end) { | ||
var str = ''; | ||
for (var a=start; a<end; a++) { | ||
var b = data2.readUInt8(a); | ||
function decode_string (data2, start, end) { | ||
let str = ''; | ||
for (let a=start; a<end; a++) { | ||
const b = data2.readUInt8(a); | ||
if (b === 0x0) break; | ||
@@ -85,3 +86,3 @@ str = str + String.fromCharCode(b); | ||
return str; | ||
}; | ||
} | ||
@@ -91,3 +92,3 @@ if (this.receive_queue.length <= 0) { | ||
} | ||
var item = this.receive_queue.shift(); | ||
const item = this.receive_queue.shift(); | ||
@@ -102,9 +103,10 @@ /////////////////// | ||
} | ||
// Status dword: 0x00 for 'bad query', 0x10 for 'OK', and 0x20 for 'no match' | ||
var st = data.readUInt32LE(4); | ||
const st = data.readUInt32LE(4); | ||
switch (st) { | ||
case (0x00): | ||
return item.cb(new Error('bad query')); | ||
case (0x10): | ||
var p0f = { | ||
case (0x10): { | ||
const p0f = { | ||
query: item.ip, | ||
@@ -127,4 +129,5 @@ first_seen: data.readUInt32LE(8), | ||
language: decode_string(data, 200, 232), | ||
}; | ||
} | ||
return item.cb(null, p0f); | ||
} | ||
case (0x20): | ||
@@ -144,8 +147,8 @@ return item.cb(null, null); | ||
} | ||
var addr = ipaddr.parse(ip); | ||
var bytes = addr.toByteArray(); | ||
var buf = new Buffer(21); | ||
const addr = ipaddr.parse(ip); | ||
const bytes = addr.toByteArray(); | ||
const buf = new Buffer(21); | ||
buf.writeUInt32LE(0x50304601, 0); // query magic | ||
buf.writeUInt8(((addr.kind() === 'ipv6') ? 0x6 : 0x4), 4); | ||
for (var i=0; i < bytes.length; i++) { | ||
for (let i=0; i < bytes.length; i++) { | ||
buf.writeUInt8(bytes[i], 5 + i); | ||
@@ -165,4 +168,4 @@ } | ||
for (var i=0; i<this.send_queue.length; i++) { | ||
var item; | ||
for (let i=0; i<this.send_queue.length; i++) { | ||
let item; | ||
if (this.socket_has_error) { | ||
@@ -182,2 +185,12 @@ item = this.send_queue.shift(); | ||
function start_p0f_client (sp, server, next) { | ||
if (!sp) { | ||
server.logerror("main.socket_path not defined in p0f.ini!"); | ||
return next(); | ||
} | ||
// Start p0f process | ||
server.notes.p0f_client = new P0FClient(sp); | ||
next(); | ||
} | ||
exports.P0FClient = P0FClient; | ||
@@ -190,3 +203,3 @@ | ||
exports.load_p0f_ini = function () { | ||
var plugin = this; | ||
const plugin = this; | ||
plugin.cfg = plugin.config.get('p0f.ini', function () { | ||
@@ -198,18 +211,11 @@ plugin.load_p0f_ini(); | ||
exports.hook_init_master = function (next, server) { | ||
var c = this.cfg.main; | ||
if (!c.socket_path) return next(); | ||
// Start p0f process? | ||
server.notes.p0f_client = new P0FClient(c.socket_path); | ||
return next(); | ||
start_p0f_client(this.cfg.main.socket_path, server, next); | ||
} | ||
exports.hook_init_child = function (next, server) { | ||
var c = this.cfg.main; | ||
if (!c.socket_path) return next(); | ||
server.notes.p0f_client = new P0FClient(c.socket_path); | ||
return next(); | ||
start_p0f_client(this.cfg.main.socket_path, server, next); | ||
}; | ||
exports.hook_lookup_rdns = function onLookup (next, connection) { | ||
var plugin = this; | ||
const plugin = this; | ||
if (connection.remote.is_private) return next(); | ||
@@ -222,4 +228,3 @@ | ||
var p0f_client = connection.server.notes.p0f_client; | ||
p0f_client.query(connection.remote.ip, function (err, result) { | ||
connection.server.notes.p0f_client.query(connection.remote.ip, (err, result) => { | ||
if (err) { | ||
@@ -237,3 +242,3 @@ connection.results.add(plugin, {err: err.message}); | ||
connection.results.add(plugin, result); | ||
return next(); | ||
next(); | ||
}); | ||
@@ -243,3 +248,3 @@ }; | ||
function format_results (r) { | ||
var data = []; | ||
const data = []; | ||
if (r.os_name) data.push('os="' + r.os_name + ' ' + r.os_flavor + '"'); | ||
@@ -254,6 +259,6 @@ if (r.link_type) data.push('link_type="' + r.link_type + '"'); | ||
exports.hook_data_post = function (next, connection) { | ||
var plugin = this; | ||
const plugin = this; | ||
if (connection.remote.is_private) return next(); | ||
var header_name = plugin.cfg.main.add_header; | ||
const header_name = plugin.cfg.main.add_header; | ||
if (!header_name) { | ||
@@ -265,3 +270,3 @@ connection.logdebug(plugin, 'header disabled in ini' ); | ||
connection.transaction.remove_header(header_name); | ||
var result = connection.results.get('p0f'); | ||
const result = connection.results.get('p0f'); | ||
if (!result || !result.os_name) { | ||
@@ -275,3 +280,3 @@ connection.results.add(plugin, {err: 'no p0f note'}); | ||
return next(); | ||
}; | ||
next(); | ||
} |
{ | ||
"name": "haraka-plugin-p0f", | ||
"version": "1.0.1", | ||
"version": "1.0.2", | ||
"description": "Haraka plugin that adds TCP fingerprinting", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -6,3 +6,2 @@ [![Build Status][ci-img]][ci-url] | ||
[![NPM][npm-img]][npm-url] | ||
<!-- doesn't work in haraka plugins... yet. [![Code Coverage][cov-img]][cov-url]--> | ||
@@ -57,2 +56,3 @@ # haraka-plugin-p0f | ||
At a minimum, [main]socket_path must be defined. | ||
@@ -59,0 +59,0 @@ ## Startup |
// node.js built-in modules | ||
const assert = require('assert'); | ||
const assert = require('assert') | ||
// npm modules | ||
const fixtures = require('haraka-test-fixtures'); | ||
const fixtures = require('haraka-test-fixtures') | ||
@@ -12,20 +12,59 @@ // start of tests | ||
beforeEach(function (done) { | ||
this.plugin = new fixtures.plugin('p0f'); | ||
done(); // if a test hangs, assure you called done() | ||
}); | ||
beforeEach((done) => { | ||
this.plugin = new fixtures.plugin('p0f') | ||
done() | ||
}) | ||
describe('p0f', function () { | ||
it('loads', function (done) { | ||
assert.ok(this.plugin); | ||
done(); | ||
}); | ||
}); | ||
describe('p0f', () => { | ||
it('loads', (done) => { | ||
assert.ok(this.plugin) | ||
done() | ||
}) | ||
}) | ||
describe('load_p0f_ini', function () { | ||
it('loads p0f.ini from config/p0f.ini', function (done) { | ||
this.plugin.load_p0f_ini(); | ||
assert.ok(this.plugin.cfg); | ||
done(); | ||
}); | ||
}); | ||
describe('load_p0f_ini', () => { | ||
it('loads p0f.ini from config/p0f.ini', (done) => { | ||
this.plugin.load_p0f_ini() | ||
assert.ok(this.plugin.cfg) | ||
done() | ||
}) | ||
}) | ||
describe('lookup_rdns', () => { | ||
it.skip('retrieves TCP fingerprint data from p0f server', function (done) { | ||
done() | ||
}) | ||
}) | ||
describe('data_post', () => { | ||
beforeEach((done) => { | ||
this.plugin = new fixtures.plugin('p0f') | ||
this.plugin.load_p0f_ini() | ||
this.plugin.cfg.main.add_header = true | ||
this.connection = new fixtures.connection.createConnection() | ||
this.connection.transaction = new fixtures.transaction.createTransaction() | ||
this.connection.results.add({ name: 'p0f' }, { os_name: 'BeOS', os_flavor: 'forever'}) | ||
done() | ||
}) | ||
it('adds a header when data exists', (done) => { | ||
this.plugin.hook_data_post((code, value) => { | ||
assert.ok(Object.keys(this.connection.transaction.header.headers)) | ||
done() | ||
}, | ||
this.connection) | ||
}) | ||
it('ignores private IPs', (done) => { | ||
this.connection.remote.is_private=true; | ||
this.plugin.hook_data_post((code, value) => { | ||
assert.equal(code, undefined) | ||
assert.equal(value, undefined) | ||
assert.equal(Object.keys(this.connection.transaction.header.headers), 0) | ||
done() | ||
}, | ||
this.connection) | ||
}) | ||
}) |
Sorry, the diff of this file is not supported yet
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
17625
298
1