aedes-protocol-decoder
Advanced tools
Comparing version 1.0.0 to 2.0.0
@@ -7,3 +7,4 @@ 'use strict' | ||
var proxyProtocol = require('proxy-protocol-js') | ||
var protocolDecoder = require('./lib/protocol-decoder') | ||
var { createServer } = require('aedes-server-factory') | ||
var { extractSocketDetails, protocolDecoder } = require('./index') | ||
@@ -123,7 +124,3 @@ var brokerPort = 4883 | ||
var broker = aedes({ | ||
decodeProtocol: function (client, buffer) { | ||
var proto = protocolDecoder(client, buffer) | ||
return proto | ||
}, | ||
preConnect: function (client, done) { | ||
preConnect: function (client, packet, done) { | ||
console.log('Aedes preConnect check client ip:', client.connDetails) | ||
@@ -134,8 +131,7 @@ if (client.connDetails && client.connDetails.ipAddress) { | ||
client.close() | ||
return done(null, true) | ||
}, | ||
trustProxy: true | ||
done(null, true) | ||
} | ||
}) | ||
var server = require('net').createServer(broker.handle) | ||
var server = createServer(broker, { trustProxy: true, extractSocketDetails, protocolDecoder }) | ||
@@ -142,0 +138,0 @@ server.listen(brokerPort, function () { |
129
index.js
@@ -1,5 +0,132 @@ | ||
var protocolDecoder = require('./lib/protocol-decoder') | ||
'use strict' | ||
const proxyProtocol = require('proxy-protocol-js') | ||
const forwarded = require('forwarded') | ||
const v1ProxyProtocolSignature = Buffer.from('PROXY ', 'utf8') | ||
const v2ProxyProtocolSignature = Buffer.from('0d0a0d0a000d0a515549540a', 'hex') | ||
function isValidV1ProxyProtocol (buffer) { | ||
for (let i = 0; i < v1ProxyProtocolSignature.length; i++) { | ||
if (buffer[i] !== v1ProxyProtocolSignature[i]) { | ||
return false | ||
} | ||
} | ||
return true | ||
} | ||
function isValidV2ProxyProtocol (buffer) { | ||
for (let i = 0; i < v2ProxyProtocolSignature.length; i++) { | ||
if (buffer[i] !== v2ProxyProtocolSignature[i]) { | ||
return false | ||
} | ||
} | ||
return true | ||
} | ||
// from https://stackoverflow.com/questions/57077161/how-do-i-convert-hex-buffer-to-ipv6-in-javascript | ||
function parseIpV6Array (ip) { | ||
const ipHex = Buffer.from(ip).toString('hex') | ||
return ipHex.match(/.{1,4}/g) | ||
.map((val) => val.replace(/^0+/, '')) | ||
.join(':') | ||
.replace(/0000:/g, ':') | ||
.replace(/:{2,}/g, '::') | ||
} | ||
function getProtoIpFamily (ipFamily) { | ||
if (ipFamily && ipFamily.endsWith('4')) { | ||
return 4 | ||
} else if (ipFamily && ipFamily.endsWith('6')) { | ||
return 6 | ||
} | ||
return 0 | ||
} | ||
function extractHttpDetails (req, socket, proto = {}) { | ||
const headers = req && req.headers ? req.headers : null | ||
if (headers) { | ||
if (headers['x-forwarded-for']) { | ||
const addresses = forwarded(req) | ||
proto.ipAddress = headers['x-real-ip'] ? headers['x-real-ip'] : addresses[addresses.length - 1] | ||
proto.serverIpAddress = addresses[0] | ||
} | ||
if (headers['x-real-ip']) { | ||
proto.ipAddress = headers['x-real-ip'] | ||
} | ||
proto.port = socket._socket.remotePort | ||
proto.ipFamily = getProtoIpFamily(socket._socket.remoteFamily) | ||
proto.isWebsocket = true | ||
} | ||
return proto | ||
} | ||
function extractProxyDetails (buffer, proto = {}) { | ||
let proxyProto | ||
if (isValidV1ProxyProtocol(buffer)) { | ||
proxyProto = proxyProtocol.V1BinaryProxyProtocol.parse(buffer) | ||
if (proxyProto && proxyProto.source && proxyProto.data) { | ||
proto.ipFamily = getProtoIpFamily(proxyProto.inetProtocol) | ||
proto.ipAddress = proxyProto.source.ipAddress | ||
proto.port = proxyProto.source.port | ||
proto.serverIpAddress = proxyProto.destination.ipAddress | ||
proto.data = proxyProto.data | ||
proto.isProxy = 1 | ||
} | ||
} else if (isValidV2ProxyProtocol(buffer)) { | ||
proxyProto = proxyProtocol.V2ProxyProtocol.parse(buffer) | ||
if (proxyProto && proxyProto.proxyAddress && proxyProto.data) { | ||
if (proxyProto.proxyAddress instanceof proxyProtocol.IPv4ProxyAddress) { | ||
proto.ipAddress = proxyProto.proxyAddress.sourceAddress.address.join('.') | ||
proto.port = proxyProto.proxyAddress.sourcePort | ||
proto.serverIpAddress = proxyProto.proxyAddress.destinationAddress.address.join('.') | ||
proto.ipFamily = 4 | ||
} else if (proxyProto.proxyAddress instanceof proxyProtocol.IPv6ProxyAddress) { | ||
proto.ipAddress = parseIpV6Array(proxyProto.proxyAddress.sourceAddress.address) | ||
proto.port = proxyProto.proxyAddress.sourcePort | ||
proto.serverIpAddress = parseIpV6Array(proxyProto.proxyAddress.destinationAddress.address) | ||
proto.ipFamily = 6 | ||
} | ||
proto.isProxy = 2 | ||
proto.data = Buffer.isBuffer(proxyProto.data) ? proxyProto.data : Buffer.from(proxyProto.data) | ||
} | ||
} | ||
return proto | ||
} | ||
function extractSocketDetails (socket, proto = {}) { | ||
if (socket._socket && socket._socket.address) { | ||
proto.isWebsocket = true | ||
proto.ipAddress = socket._socket.remoteAddress | ||
proto.port = socket._socket.remotePort | ||
proto.serverIpAddress = socket._socket.address().address | ||
proto.ipFamily = getProtoIpFamily(socket._socket.remoteFamily) | ||
} else if (socket.address) { | ||
proto.ipAddress = socket.remoteAddress | ||
proto.port = socket.remotePort | ||
proto.serverIpAddress = socket.address().address | ||
proto.ipFamily = getProtoIpFamily(socket.remoteFamily) | ||
} | ||
return proto | ||
} | ||
function protocolDecoder (conn, buffer, req) { | ||
const proto = {} | ||
if (!buffer) return proto | ||
const socket = conn.socket || conn | ||
proto.isProxy = 0 | ||
proto.isWebsocket = false | ||
extractHttpDetails(req, socket, proto) | ||
extractProxyDetails(buffer, proto) | ||
if (!proto.ipAddress) { | ||
extractSocketDetails(socket, proto) | ||
} | ||
return proto | ||
} | ||
module.exports = { | ||
extractSocketDetails, | ||
protocolDecoder | ||
} |
{ | ||
"name": "aedes-protocol-decoder", | ||
"version": "1.0.0", | ||
"version": "2.0.0", | ||
"description": "Aedes plugin to decode connection frame and validate proxies", | ||
@@ -29,3 +29,3 @@ "main": "index.js", | ||
"engines": { | ||
"node": ">=8" | ||
"node": ">=10" | ||
}, | ||
@@ -68,23 +68,23 @@ "release-it": { | ||
"devDependencies": { | ||
"@types/node": "^12.12.25", | ||
"@typescript-eslint/eslint-plugin": "^2.17.0", | ||
"@typescript-eslint/parser": "^2.17.0", | ||
"aedes": "git+https://git@github.com/moscajs/aedes.git#master", | ||
"@types/node": "^14.0.1", | ||
"@typescript-eslint/eslint-plugin": "^2.30.0", | ||
"@typescript-eslint/parser": "^2.30.0", | ||
"aedes": "^0.44.0", | ||
"aedes-server-factory": "git+https://git@github.com/getlarge/aedes-server-factory.git#create-server-factory", | ||
"faucet": "0.0.1", | ||
"license-checker": "^25.0.1", | ||
"mqtt": "^3.0.0", | ||
"mqtt-packet": "^6.3.0", | ||
"mqtt": "^4.0.0", | ||
"mqtt-packet": "^6.5.0", | ||
"nyc": "^15.0.0", | ||
"pre-commit": "^1.2.2", | ||
"release-it": "^12.4.3", | ||
"release-it": "^14.0.2", | ||
"snazzy": "^8.0.0", | ||
"standard": "^14.3.1", | ||
"standard": "^14.3.3", | ||
"tape": "^4.13.0", | ||
"typescript": "^3.7.5", | ||
"websocket-stream": "^5.5.0" | ||
"typescript": "^4.0.2" | ||
}, | ||
"dependencies": { | ||
"forwarded": "^0.1.2", | ||
"proxy-protocol-js": "^4.0.3" | ||
"proxy-protocol-js": "^4.0.5" | ||
} | ||
} |
@@ -17,6 +17,6 @@ # aedes-protocol-decoder | ||
The purpose of this module is to be used inside [aedes](https://github.com/moscajs/aedes) `decodeProtocol` hook, which is called when aedes instance receives a first valid buffer from client ( before CONNECT packet). The client object state is in default and its connected state is false. | ||
The function extract socket details and if aedes `trustProxy` option is set to true, it will first parse http headers (x-real-ip | x-forwarded-for) and proxy protocol (v1 and v2) to retrieve information in client.connDetails. | ||
The purpose of this module is to be used inside [aedes-server-factory](https://github.com/moscajs/aedes-server-factory) `bindConnection` function, which is called when the server receives a connection from client (before CONNECT packet). The client object state is in default and its connected state is false. | ||
The function extract socket details and if `aedes-server-factory` `trustProxy` option is set to true, it will first parse http headers (x-real-ip | x-forwarded-for) and/or proxy protocol (v1 and v2), then passing the informations to `aedes` that will assign them to `client.connDetails`. | ||
The function `protocolDecoder` returns [ConnectionDetails](./types/index.d.ts), if the object contains data property, it will be parsed as an mqtt-packet. | ||
The function `protocolDecoder` and `extractSocketDetails` returns [ConnectionDetails](./types/index.d.ts), if the object contains `data` property, it will be parsed as an [mqtt-packet](https://github.com/mqttjs/mqtt-packet). | ||
@@ -34,11 +34,7 @@ ## Install | ||
var { protocolDecoder } = require('aedes-protocol-decoder') | ||
var net = require('net') | ||
var { createServer } = require('aedes-server-factory') | ||
var port = 1883 | ||
var broker = aedes({ | ||
decodeProtocol: function (client, buffer) { | ||
var proto = protocolDecoder(client, buffer) | ||
return proto | ||
}, | ||
preConnect: function (client, done) { | ||
preConnect: function (client, packet, done) { | ||
if (client.connDetails && client.connDetails.ipAddress) { | ||
@@ -49,12 +45,8 @@ client.ip = client.connDetails.ipAddress | ||
}, | ||
trustProxy: true | ||
}) | ||
var server = net.createServer(broker.handle) | ||
var server = createServer(broker, { trustProxy: true, protocolDecoder }) | ||
server.listen(port, function () { | ||
console.log('server listening on port', port) | ||
}) | ||
``` | ||
@@ -61,0 +53,0 @@ |
554
test.js
@@ -5,4 +5,3 @@ 'use strict' | ||
var aedes = require('aedes') | ||
var http = require('http') | ||
var ws = require('websocket-stream') | ||
var { createServer } = require('aedes-server-factory') | ||
var mqtt = require('mqtt') | ||
@@ -12,5 +11,84 @@ var mqttPacket = require('mqtt-packet') | ||
var proxyProtocol = require('proxy-protocol-js') | ||
var protocolDecoder = require('./lib/protocol-decoder') | ||
var { extractSocketDetails, protocolDecoder } = require('./index') | ||
// test ipAddress property presence when trustProxy is enabled | ||
function start (options) { | ||
var broker | ||
var server | ||
var client | ||
if (options.broker) { | ||
broker = aedes(options.broker) | ||
} | ||
if (options.server) { | ||
server = createServer(broker, options.server) | ||
} | ||
if (options.client) { | ||
client = mqtt.connect(options.client) | ||
} | ||
return { broker, client, server } | ||
} | ||
function close ({ broker, client, server }, t) { | ||
if (client) { | ||
client.end(true) | ||
} | ||
if (broker) { | ||
broker.close() | ||
} | ||
if (server) { | ||
server.close() | ||
} | ||
if (t) { | ||
t.end() | ||
} | ||
} | ||
function generateProxyConnectPacket (clientIp, serverPort, proxyVersion = 1, ipFamily = 4) { | ||
var packet = { | ||
cmd: 'connect', | ||
protocolId: 'MQTT', | ||
protocolVersion: 4, | ||
clean: true, | ||
clientId: 'my-client-proxyV1', | ||
keepalive: 0 | ||
} | ||
if (proxyVersion === 1 && ipFamily === 4) { | ||
var src = new proxyProtocol.Peer(clientIp, 12345) | ||
var dst = new proxyProtocol.Peer('127.0.0.1', serverPort) | ||
return new proxyProtocol.V1BinaryProxyProtocol( | ||
proxyProtocol.INETProtocol.TCP4, | ||
src, | ||
dst, | ||
mqttPacket.generate(packet) | ||
).build() | ||
} else if (proxyVersion === 2 && ipFamily === 4) { | ||
return new proxyProtocol.V2ProxyProtocol( | ||
proxyProtocol.Command.LOCAL, | ||
proxyProtocol.TransportProtocol.DGRAM, | ||
new proxyProtocol.IPv4ProxyAddress( | ||
proxyProtocol.IPv4Address.createFrom(clientIp.split('.')), | ||
12345, | ||
proxyProtocol.IPv4Address.createFrom([127, 0, 0, 1]), | ||
serverPort | ||
), | ||
mqttPacket.generate(packet) | ||
).build() | ||
} else if (proxyVersion === 2 && ipFamily === 6) { | ||
return new proxyProtocol.V2ProxyProtocol( | ||
proxyProtocol.Command.PROXY, | ||
proxyProtocol.TransportProtocol.STREAM, | ||
new proxyProtocol.IPv6ProxyAddress( | ||
proxyProtocol.IPv6Address.createFrom(clientIp), | ||
12345, | ||
proxyProtocol.IPv6Address.createWithEmptyAddress(), | ||
serverPort | ||
), | ||
mqttPacket.generate(packet) | ||
).build() | ||
} | ||
return null | ||
} | ||
test('tcp clients have access to the ipAddress from the socket', function (t) { | ||
@@ -20,38 +98,29 @@ t.plan(2) | ||
var port = 4883 | ||
var broker = aedes({ | ||
decodeProtocol: function (client, buffer) { | ||
var proto = protocolDecoder(client, buffer) | ||
return proto | ||
}, | ||
preConnect: function (client, done) { | ||
if (client && client.connDetails && client.connDetails.ipAddress) { | ||
client.ip = client.connDetails.ipAddress | ||
t.equal('::ffff:127.0.0.1', client.ip) | ||
} else { | ||
t.fail('no ip address present') | ||
var setup = start({ | ||
broker: { | ||
preConnect: function (client, packet, done) { | ||
if (client && client.connDetails && client.connDetails.ipAddress) { | ||
client.ip = client.connDetails.ipAddress | ||
t.equal('::ffff:127.0.0.1', client.ip) | ||
} else { | ||
t.fail('no ip address present') | ||
} | ||
done(null, true) | ||
close(setup, t) | ||
} | ||
done(null, true) | ||
setImmediate(finish) | ||
}, | ||
trustProxy: true | ||
server: { | ||
trustProxy: false, extractSocketDetails, protocolDecoder | ||
}, | ||
client: { | ||
port, | ||
keepalive: 0, | ||
clientId: 'mqtt-client', | ||
clean: false | ||
} | ||
}) | ||
var server = net.createServer(broker.handle) | ||
server.listen(port, function (err) { | ||
setup.server.listen(port, function (err) { | ||
t.error(err, 'no error') | ||
}) | ||
var client = mqtt.connect({ | ||
port, | ||
keepalive: 0, | ||
clientId: 'mqtt-client', | ||
clean: false | ||
}) | ||
function finish () { | ||
client.end() | ||
broker.close() | ||
server.close() | ||
t.end() | ||
} | ||
}) | ||
@@ -64,44 +133,26 @@ | ||
var clientIp = '192.168.0.140' | ||
var packet = { | ||
cmd: 'connect', | ||
protocolId: 'MQIsdp', | ||
protocolVersion: 3, | ||
clean: true, | ||
clientId: 'my-client-proxyV1', | ||
keepalive: 0 | ||
} | ||
var buf = mqttPacket.generate(packet) | ||
var src = new proxyProtocol.Peer(clientIp, 12345) | ||
var dst = new proxyProtocol.Peer('127.0.0.1', port) | ||
var protocol = new proxyProtocol.V1BinaryProxyProtocol( | ||
proxyProtocol.INETProtocol.TCP4, | ||
src, | ||
dst, | ||
buf | ||
).build() | ||
var broker = aedes({ | ||
decodeProtocol: function (client, buffer) { | ||
var proto = protocolDecoder(client, buffer) | ||
return proto | ||
}, | ||
preConnect: function (client, done) { | ||
if (client.connDetails && client.connDetails.ipAddress) { | ||
client.ip = client.connDetails.ipAddress | ||
t.equal(clientIp, client.ip) | ||
} else { | ||
t.fail('no ip address present') | ||
var setup = start({ | ||
broker: { | ||
preConnect: function (client, packet, done) { | ||
if (client.connDetails && client.connDetails.ipAddress) { | ||
client.ip = client.connDetails.ipAddress | ||
t.equal(clientIp, client.ip) | ||
} else { | ||
t.fail('no ip address present') | ||
} | ||
done(null, true) | ||
finish() | ||
} | ||
done(null, true) | ||
setImmediate(finish) | ||
}, | ||
trustProxy: true | ||
server: { | ||
trustProxy: true, extractSocketDetails, protocolDecoder | ||
} | ||
}) | ||
var server = net.createServer(broker.handle) | ||
server.listen(port, function (err) { | ||
setup.server.listen(port, function (err) { | ||
t.error(err, 'no error') | ||
}) | ||
var proxyPacket = generateProxyConnectPacket(clientIp, port, 1, 4) | ||
var client = net.connect({ | ||
@@ -111,3 +162,3 @@ port, | ||
}, function () { | ||
client.write(protocol) | ||
client.write(proxyPacket) | ||
}) | ||
@@ -117,5 +168,3 @@ | ||
client.end() | ||
broker.close() | ||
server.close() | ||
t.end() | ||
close(setup, t) | ||
} | ||
@@ -129,45 +178,26 @@ }) | ||
var clientIp = '192.168.0.140' | ||
var packet = { | ||
cmd: 'connect', | ||
protocolId: 'MQTT', | ||
protocolVersion: 4, | ||
clean: true, | ||
clientId: 'my-client-proxyV2' | ||
} | ||
var protocol = new proxyProtocol.V2ProxyProtocol( | ||
proxyProtocol.Command.LOCAL, | ||
proxyProtocol.TransportProtocol.DGRAM, | ||
new proxyProtocol.IPv4ProxyAddress( | ||
proxyProtocol.IPv4Address.createFrom(clientIp.split('.')), | ||
12345, | ||
proxyProtocol.IPv4Address.createFrom([127, 0, 0, 1]), | ||
port | ||
), | ||
mqttPacket.generate(packet) | ||
).build() | ||
var broker = aedes({ | ||
decodeProtocol: function (client, buffer) { | ||
var proto = protocolDecoder(client, buffer) | ||
return proto | ||
}, | ||
preConnect: function (client, done) { | ||
if (client.connDetails && client.connDetails.ipAddress) { | ||
client.ip = client.connDetails.ipAddress | ||
t.equal(clientIp, client.ip) | ||
} else { | ||
t.fail('no ip address present') | ||
var setup = start({ | ||
broker: { | ||
preConnect: function (client, packet, done) { | ||
if (client.connDetails && client.connDetails.ipAddress) { | ||
client.ip = client.connDetails.ipAddress | ||
t.equal(clientIp, client.ip) | ||
} else { | ||
t.fail('no ip address present') | ||
} | ||
done(null, true) | ||
finish() | ||
} | ||
done(null, true) | ||
setImmediate(finish) | ||
}, | ||
trustProxy: true | ||
server: { | ||
trustProxy: true, extractSocketDetails, protocolDecoder | ||
} | ||
}) | ||
var server = net.createServer(broker.handle) | ||
server.listen(port, function (err) { | ||
setup.server.listen(port, function (err) { | ||
t.error(err, 'no error') | ||
}) | ||
var proxyPacket = generateProxyConnectPacket(clientIp, port, 2, 4) | ||
var client = net.createConnection( | ||
@@ -178,3 +208,3 @@ { | ||
}, function () { | ||
client.write(Buffer.from(protocol)) | ||
client.write(proxyPacket) | ||
} | ||
@@ -185,5 +215,3 @@ ) | ||
client.end() | ||
broker.close() | ||
server.close() | ||
t.end() | ||
close(setup, t) | ||
} | ||
@@ -198,45 +226,26 @@ }) | ||
var clientIp = '::ffff:c0a8:180:' | ||
var packet = { | ||
cmd: 'connect', | ||
protocolId: 'MQTT', | ||
protocolVersion: 4, | ||
clean: true, | ||
clientId: 'my-client-proxyV2' | ||
} | ||
var protocol = new proxyProtocol.V2ProxyProtocol( | ||
proxyProtocol.Command.PROXY, | ||
proxyProtocol.TransportProtocol.STREAM, | ||
new proxyProtocol.IPv6ProxyAddress( | ||
proxyProtocol.IPv6Address.createFrom(clientIpArray), | ||
12345, | ||
proxyProtocol.IPv6Address.createWithEmptyAddress(), | ||
port | ||
), | ||
mqttPacket.generate(packet) | ||
).build() | ||
var broker = aedes({ | ||
decodeProtocol: function (client, buffer) { | ||
var proto = protocolDecoder(client, buffer) | ||
return proto | ||
}, | ||
preConnect: function (client, done) { | ||
if (client.connDetails && client.connDetails.ipAddress) { | ||
client.ip = client.connDetails.ipAddress | ||
t.equal(clientIp, client.ip) | ||
} else { | ||
t.fail('no ip address present') | ||
var setup = start({ | ||
broker: { | ||
preConnect: function (client, packet, done) { | ||
if (client.connDetails && client.connDetails.ipAddress) { | ||
client.ip = client.connDetails.ipAddress | ||
t.equal(clientIp, client.ip) | ||
} else { | ||
t.fail('no ip address present') | ||
} | ||
done(null, true) | ||
finish() | ||
} | ||
done(null, true) | ||
setImmediate(finish) | ||
}, | ||
trustProxy: true | ||
server: { | ||
trustProxy: true, extractSocketDetails, protocolDecoder | ||
} | ||
}) | ||
var server = net.createServer(broker.handle) | ||
server.listen(port, function (err) { | ||
setup.server.listen(port, function (err) { | ||
t.error(err, 'no error') | ||
}) | ||
var proxyPacket = generateProxyConnectPacket(clientIpArray, port, 2, 6) | ||
var client = net.createConnection( | ||
@@ -247,3 +256,3 @@ { | ||
}, function () { | ||
client.write(Buffer.from(protocol)) | ||
client.write(proxyPacket) | ||
} | ||
@@ -254,5 +263,3 @@ ) | ||
client.end() | ||
broker.close() | ||
server.close() | ||
t.end() | ||
close(setup, t) | ||
} | ||
@@ -266,37 +273,25 @@ }) | ||
var port = 4883 | ||
var broker = aedes({ | ||
decodeProtocol: function (client, buffer) { | ||
var proto = protocolDecoder(client, buffer) | ||
return proto | ||
}, | ||
preConnect: function (client, done) { | ||
if (client.connDetails && client.connDetails.ipAddress) { | ||
client.ip = client.connDetails.ipAddress | ||
t.equal(clientIp, client.ip) | ||
} else { | ||
t.fail('no ip address present') | ||
var setup = start({ | ||
broker: { | ||
preConnect: function (client, packet, done) { | ||
if (client.connDetails && client.connDetails.ipAddress) { | ||
client.ip = client.connDetails.ipAddress | ||
t.equal(clientIp, client.ip) | ||
} else { | ||
t.fail('no ip address present') | ||
} | ||
done(null, true) | ||
close(setup, t) | ||
} | ||
done(null, true) | ||
setImmediate(finish) | ||
}, | ||
trustProxy: true | ||
server: { | ||
ws: true, trustProxy: false, extractSocketDetails, protocolDecoder | ||
}, | ||
client: `ws://localhost:${port}` | ||
}) | ||
var server = http.createServer() | ||
ws.createServer({ | ||
server: server | ||
}, broker.handle) | ||
server.listen(port, function (err) { | ||
setup.server.listen(port, function (err) { | ||
t.error(err, 'no error') | ||
}) | ||
var client = mqtt.connect(`ws://localhost:${port}`) | ||
function finish () { | ||
broker.close() | ||
server.close() | ||
client.end() | ||
t.end() | ||
} | ||
}) | ||
@@ -309,43 +304,34 @@ | ||
var port = 4883 | ||
var broker = aedes({ | ||
decodeProtocol: function (client, buffer) { | ||
var proto = protocolDecoder(client, buffer) | ||
return proto | ||
var setup = start({ | ||
broker: { | ||
preConnect: function (client, packet, done) { | ||
if (client.connDetails && client.connDetails.ipAddress) { | ||
client.ip = client.connDetails.ipAddress | ||
t.equal(clientIp, client.ip) | ||
} else { | ||
t.fail('no ip address present') | ||
} | ||
done(null, true) | ||
close(setup, t) | ||
} | ||
}, | ||
preConnect: function (client, done) { | ||
if (client.connDetails && client.connDetails.ipAddress) { | ||
client.ip = client.connDetails.ipAddress | ||
t.equal(clientIp, client.ip) | ||
} else { | ||
t.fail('no ip address present') | ||
server: { | ||
ws: true, trustProxy: true, extractSocketDetails, protocolDecoder | ||
}, | ||
client: { | ||
protocol: 'ws', | ||
host: 'localhost', | ||
port, | ||
wsOptions: { | ||
headers: { | ||
'X-Real-Ip': clientIp | ||
} | ||
} | ||
done(null, true) | ||
setImmediate(finish) | ||
}, | ||
trustProxy: true | ||
} | ||
}) | ||
var server = http.createServer() | ||
ws.createServer({ | ||
server: server | ||
}, broker.handle) | ||
server.listen(port, function (err) { | ||
setup.server.listen(port, function (err) { | ||
t.error(err, 'no error') | ||
}) | ||
var client = mqtt.connect(`ws://localhost:${port}`, { | ||
wsOptions: { | ||
headers: { | ||
'X-Real-Ip': clientIp | ||
} | ||
} | ||
}) | ||
function finish () { | ||
broker.close() | ||
server.close() | ||
client.end() | ||
t.end() | ||
} | ||
}) | ||
@@ -358,43 +344,34 @@ | ||
var port = 4883 | ||
var broker = aedes({ | ||
decodeProtocol: function (client, buffer) { | ||
var proto = protocolDecoder(client, buffer) | ||
return proto | ||
var setup = start({ | ||
broker: { | ||
preConnect: function (client, packet, done) { | ||
if (client.connDetails && client.connDetails.ipAddress) { | ||
client.ip = client.connDetails.ipAddress | ||
t.equal(clientIp, client.ip) | ||
} else { | ||
t.fail('no ip address present') | ||
} | ||
done(null, true) | ||
close(setup, t) | ||
} | ||
}, | ||
preConnect: function (client, done) { | ||
if (client.connDetails && client.connDetails.ipAddress) { | ||
client.ip = client.connDetails.ipAddress | ||
t.equal(clientIp, client.ip) | ||
} else { | ||
t.fail('no ip address present') | ||
server: { | ||
ws: true, trustProxy: true, extractSocketDetails, protocolDecoder | ||
}, | ||
client: { | ||
protocol: 'ws', | ||
host: 'localhost', | ||
port, | ||
wsOptions: { | ||
headers: { | ||
'X-Forwarded-For': clientIp | ||
} | ||
} | ||
done(null, true) | ||
setImmediate(finish) | ||
}, | ||
trustProxy: true | ||
} | ||
}) | ||
var server = http.createServer() | ||
ws.createServer({ | ||
server: server | ||
}, broker.handle) | ||
server.listen(port, function (err) { | ||
setup.server.listen(port, function (err) { | ||
t.error(err, 'no error') | ||
}) | ||
var client = mqtt.connect(`ws://localhost:${port}`, { | ||
wsOptions: { | ||
headers: { | ||
'X-Forwarded-For': clientIp | ||
} | ||
} | ||
}) | ||
function finish () { | ||
broker.close() | ||
server.close() | ||
client.end() | ||
t.end() | ||
} | ||
}) | ||
@@ -408,35 +385,33 @@ | ||
var clientIp = '192.168.0.140' | ||
var packet = { | ||
cmd: 'connect', | ||
protocolId: 'MQIsdp', | ||
protocolVersion: 3, | ||
clean: true, | ||
clientId: 'my-client-proxyV1', | ||
keepalive: 0 | ||
} | ||
var buf = mqttPacket.generate(packet) | ||
var src = new proxyProtocol.Peer(clientIp, 12345) | ||
var dst = new proxyProtocol.Peer('127.0.0.1', proxyPort) | ||
var broker = aedes({ | ||
decodeProtocol: function (client, buff) { | ||
var proto = protocolDecoder(client, buff) | ||
if (proto.data) { | ||
t.equal(proto.data.toString(), buf.toString()) | ||
} else { | ||
t.fail('no MQTT packet extracted from TCP buffer') | ||
var setup = start({ | ||
broker: { | ||
preConnect: function (client, packet, done) { | ||
if (client.connDetails.data) { | ||
const parser = mqttPacket.parser({ protocolVersion: 3 }) | ||
parser.on('packet', (parsedPacket) => { | ||
t.equal(JSON.stringify(parsedPacket), JSON.stringify(packet)) | ||
done(null, true) | ||
}) | ||
parser.on('error', () => { | ||
t.fail('no valid MQTT packet extracted from TCP buffer') | ||
done(null, true) | ||
}) | ||
parser.parse(client.connDetails.data) | ||
} else { | ||
t.fail('no MQTT packet extracted from TCP buffer') | ||
done(null, true) | ||
} | ||
} | ||
return proto | ||
}, | ||
trustProxy: true | ||
server: { | ||
trustProxy: true, extractSocketDetails, protocolDecoder | ||
} | ||
}) | ||
broker.on('clientDisconnect', function (client) { | ||
// console.log('onClientDisconnect', client.id) | ||
setImmediate(finish) | ||
setup.broker.on('clientDisconnect', function () { | ||
finish() | ||
}) | ||
var server = net.createServer(broker.handle) | ||
server.listen(brokerPort, function (err) { | ||
setup.server.listen(brokerPort, function (err) { | ||
t.error(err, 'no error') | ||
@@ -446,2 +421,3 @@ }) | ||
var proxyServer = net.createServer() | ||
proxyServer.listen(proxyPort, function (err) { | ||
@@ -454,6 +430,4 @@ t.error(err, 'no error') | ||
proxyServer.on('connection', function (socket) { | ||
socket.on('end', function (data) { | ||
proxyClient.end(data, function () { | ||
proxyClient.connected = false | ||
}) | ||
socket.on('end', function () { | ||
proxyClient.connected = false | ||
}) | ||
@@ -465,3 +439,5 @@ | ||
} else { | ||
var protocol = new proxyProtocol.V1BinaryProxyProtocol( | ||
var src = new proxyProtocol.Peer(clientIp, 12345) | ||
var dst = new proxyProtocol.Peer('127.0.0.1', proxyPort) | ||
var proxyPacket = new proxyProtocol.V1BinaryProxyProtocol( | ||
proxyProtocol.INETProtocol.TCP4, | ||
@@ -476,3 +452,3 @@ src, | ||
}, function () { | ||
proxyClient.write(protocol, function () { | ||
proxyClient.write(proxyPacket, function () { | ||
proxyClient.connected = true | ||
@@ -485,7 +461,16 @@ }) | ||
var packet = { | ||
cmd: 'connect', | ||
protocolId: 'MQIsdp', | ||
protocolVersion: 3, | ||
clean: true, | ||
clientId: 'my-client-proxyV1', | ||
keepalive: 0 | ||
} | ||
var client = net.connect({ | ||
port: proxyPort, | ||
timeout: 200 | ||
timeout: 250 | ||
}, function () { | ||
client.write(buf) | ||
client.write(mqttPacket.generate(packet)) | ||
}) | ||
@@ -498,4 +483,3 @@ | ||
function finish () { | ||
broker.close() | ||
server.close() | ||
close(setup) | ||
proxyServer.close() | ||
@@ -502,0 +486,0 @@ t.end() |
@@ -0,1 +1,11 @@ | ||
/* eslint no-unused-vars: 0 */ | ||
/* eslint no-undef: 0 */ | ||
/* eslint space-infix-ops: 0 */ | ||
/// <reference types="node" /> | ||
import { Socket } from 'net' | ||
import { Stream } from 'stream' | ||
export interface ConnectionDetails { | ||
@@ -11,2 +21,4 @@ ipAddress: string | ||
export type ProtocolDecoder = (client: Object, buffer: Buffer) => ConnectionDetails | null | ||
export type ProtocolDecoder = (conn: Stream, buffer: Buffer, req?: any) => ConnectionDetails | ||
export type ExtractSocketDetails = (socket: Socket) => ConnectionDetails | null |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
3
29006
8
699
54
Updatedproxy-protocol-js@^4.0.5