Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

mdns-js

Package Overview
Dependencies
Maintainers
1
Versions
31
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mdns-js - npm Package Compare versions

Comparing version 0.2.8 to 0.2.9

lib/networking.js

8

index.js

@@ -5,5 +5,6 @@

var st = require('./lib/service_type');
var Networking = require('./lib/networking');
var networking = new Networking();
/** @member {string} */

@@ -26,3 +27,3 @@ module.exports.version = config.version;

}
return new module.exports.Browser(serviceType);
return new module.exports.Browser(networking, serviceType);
};

@@ -45,3 +46,4 @@

function advertisementCreated(serviceType, port, options) {
return new module.exports.Advertisement(serviceType, port, options);
return new module.exports.Advertisement(
networking, serviceType, port, options);
};

@@ -48,0 +50,0 @@

var debug = require('debug')('mdns:advertisement');
var dgram = require('dgram');
var os = require('os');
var dns = require('mdns-js-packet');
var DNSPacket = dns.DNSPacket;
var DNSRecord = dns.DNSRecord;

@@ -14,26 +11,2 @@ var ServiceType = require('./service_type').ServiceType;

internal.sendDNSPacket = function (packet, cb) {
debug('sending %d question, %d answer',
packet.question.length, packet.answer.length);
debug('packet', packet);
var buf = DNSPacket.toBuffer(packet);
// send packet
var sock = dgram.createSocket('udp4');
sock.bind(5353, function (err) {
if (err) {
debug('there was an error binding %s', err);
return;
}
sock.addMembership('224.0.0.251');
sock.setMulticastTTL(255);
sock.setMulticastLoopback(true);
sock.send(buf, 0, buf.length, 5353, '224.0.0.251', function (err, bytes) {
debug('sent %d bytes with err:%s', bytes, err);
sock.close();
typeof cb === 'function' && cb();
});
});
};
// Array of published services.

@@ -46,151 +19,74 @@ internal.services = [];

internal.haveResponder = function () {
return (internal.services.length !== 0 || internal.probes.length !== 0);
};
internal.startResponder = function () {
var interfaces = os.networkInterfaces();
var ifaceFilter = this.options.networkInterface;
var index = 0;
for (var key in interfaces) {
if (typeof ifaceFilter === 'undefined' || key === ifaceFilter) {
if (interfaces.hasOwnProperty(key)) {
for (var i = 0; i < interfaces[key].length; i++) {
var address = interfaces[key][i].address;
debug('interface', key, interfaces[key]);
//no IPv6 addresses
if (address.indexOf(':') !== -1) {
continue;
}
// these are for unicast queries ?
createSocket(index++, key, address, 0, bindToAddress.bind(this));
}
}
}
}
// this is for multicast queries ?
createSocket(index++, '(multicast)', '224.0.0.251', 5353,
bindToAddress.bind(this));
function createSocket(interfaceIndex, networkInterface, address, port, cb) {
var sock = dgram.createSocket('udp4');
debug('creating socket for interface %s: %s:%d',
networkInterface, address, port);
sock.bind(port, address, function (err) {
if (port === 5353) {
sock.addMembership(address);
sock.setMulticastTTL(255);
sock.setMulticastLoopback(true);
}
cb(err, interfaceIndex, networkInterface, sock);
});
internal.handleQuery = function (rec) {
if (rec.type !== DNSRecord.Type.PTR &&
rec.type !== DNSRecord.Type.SRV &&
rec.type !== DNSRecord.Type.ANY) {
debug('skipping query: type not PTR/SRV/ANY');
return;
}
function bindToAddress (err, interfaceIndex, networkInterface, sock) {
if (err) {
debug('there was an error binding %s', err);
return;
}
debug('bindToAddress');
internal.connections.push(sock);
sock.on('message', function (message, remote) {
debug('got packet from remote', remote);
var packet;
try {
packet = DNSPacket.parse(message);
} catch (err) {
debug('got packet truncated package, ignoring');
return;
// check if we should reply via multi or unicast
// TODO: handle the is_qu === true case and reply directly to remote
// var is_qu = (rec.cl & DNSRecord.Class.IS_QM) === DNSRecord.Class.IS_QM;
rec.class &= ~DNSRecord.Class.IS_OM;
if (rec.class !== DNSRecord.Class.IN && rec.type !== DNSRecord.Class.ANY) {
debug('skipping query: class not IN/ANY: %d', rec.class);
return;
}
try {
var type = new ServiceType(rec.name);
internal.services.forEach(function (service) {
if (type.isWildcard() || type.matches(service.serviceType)) {
debug('answering query');
// TODO: should we only send PTR records if the query was for PTR
// records?
internal.sendDNSPacket(
pf.buildANPacket.apply(service, [DNSRecord.TTL]));
} else {
debug('skipping query; type %s not * or %s', type,
service.serviceType);
}
// check if it is a query where we are the authority for
packet.question.forEach(handleQuery.bind(this));
packet.answer.forEach(handleAnswer.bind(this));
}.bind(this));
sock.on('error', function (err) {
debug('socket error', err);
});
} catch (err) {
// invalid service type
}
};
function handleQuery(rec) {
if (rec.type !== DNSRecord.Type.PTR &&
rec.type !== DNSRecord.Type.SRV &&
rec.type !== DNSRecord.Type.ANY) {
debug('skipping query: type not PTR/SRV/ANY');
return;
}
// check if we should reply via multi or unicast
// TODO: handle the is_qu === true case and reply directly to remote
// var is_qu = (rec.cl & DNSRecord.Class.IS_QM) === DNSRecord.Class.IS_QM;
rec.class &= ~DNSRecord.Class.IS_OM;
if (rec.class !== DNSRecord.Class.IN && rec.type !== DNSRecord.Class.ANY) {
debug('skipping query: class not IN/ANY: %d', rec.class);
return;
}
try {
var type = new ServiceType(rec.name);
internal.services.forEach(function (service) {
if (type.isWildcard() || type.matches(service.serviceType)) {
debug('answering query');
// TODO: should we only send PTR records if the query was for PTR
// records?
internal.sendDNSPacket(
pf.buildANPacket.apply(service, [DNSRecord.TTL]));
} else {
debug('skipping query; type %s not * or %s', type,
service.serviceType);
internal.handleAnswer = function (rec) {
try {
internal.probes.forEach(function (service) {
if (service.status < 3) {
var conflict = false;
// parse answers and check if they match a probe
debug('check names: %s and %s', rec.name, service.alias);
switch (rec.type) {
case DNSRecord.Type.PTR:
if (rec.asName() === service.alias) {
conflict = true;
debug('name conflict in PTR');
}
break;
case DNSRecord.Type.SRV:
case DNSRecord.Type.TXT:
if (rec.name === service.alias) {
conflict = true;
debug('name conflict in SRV/TXT');
}
break;
}
});
} catch (err) {
// invalid service type
}
}
function handleAnswer(rec) {
try {
internal.probes.forEach(function (service) {
if (service.status < 3) {
var conflict = false;
// parse answers and check if they match a probe
debug('check names: %s and %s', rec.name, service.alias);
switch (rec.type) {
case DNSRecord.Type.PTR:
if (rec.asName() === service.alias) {
conflict = true;
debug('name conflict in PTR');
}
break;
case DNSRecord.Type.SRV:
case DNSRecord.Type.TXT:
if (rec.name === service.alias) {
conflict = true;
debug('name conflict in SRV/TXT');
}
break;
}
if (conflict) {
// no more probes
service.status = 4;
}
if (conflict) {
// no more probes
service.status = 4;
}
});
} catch (err) {
// invalid service type
}
}
});
} catch (err) {
// invalid service type
}
};
internal.stopResponder = function () {
debug('stopping %d sockets', internal.connections.length);
for (var i = 0; i < internal.connections.length; i++) {
var sock = internal.connections[i];
sock.close();
sock.unref();
}
internal.connections = [];
};
internal.probeAndAdvertise = function () {
debug('probeAndAdvertise(%s)', this.status);
switch (this.status) {

@@ -201,12 +97,11 @@ case 0:

debug('probing service %d', this.status + 1);
internal.sendDNSPacket(pf.buildQDPacket.apply(this, []));
this.networking.send(pf.buildQDPacket.apply(this, []));
break;
case 3:
debug('publishing service, suffix=%s', this.nameSuffix);
internal.sendDNSPacket(
pf.buildANPacket.apply(this, [DNSRecord.TTL]));
var packet = pf.buildANPacket.apply(this, [DNSRecord.TTL]);
this.networking.send(packet);
// Repost announcement after 1sec (see rfc6762: 8.3)
setTimeout(function onTimeout() {
internal.sendDNSPacket(
pf.buildANPacket.apply(this, [DNSRecord.TTL]));
this.networking.send(packet);
}.bind(this), 1000);

@@ -241,3 +136,4 @@ // Service has been registered, respond to matching queries

*/
var Advertisement = module.exports = function (serviceType, port, options) {
var Advertisement = module.exports = function (
networking, serviceType, port, options) {
if (!(this instanceof Advertisement)) {

@@ -247,2 +143,3 @@ return new Advertisement(serviceType, port, options);

// TODO: check more parameters

@@ -252,2 +149,3 @@ if (!('name' in options)) {

}
var self = this;
this.serviceType = serviceType;

@@ -259,24 +157,31 @@ this.port = port;

this.status = 0; // inactive
this.networking = networking;
networking.on('packets', function (packets /*, remote, connection*/) {
packets.forEach(function (packet) {
packet.question.forEach(internal.handleQuery.bind(self));
packet.answer.forEach(internal.handleAnswer.bind(self));
});
});
this.start = function () {
networking.addUsage(self, function () {
internal.probes.push(self);
internal.probeAndAdvertise.apply(self, []);
});
};
this.stop = function () {
debug('unpublishing service');
internal.services =
internal.services.filter(function (service) { return service === self; });
networking.send(pf.buildANPacket.apply(self, [0]));
this.nameSuffix = '';
this.alias = '';
this.status = 0; // inactive
};
debug('created new service');
}; //--Advertisement constructor
Advertisement.prototype.start = function () {
if (!internal.haveResponder()) {
internal.startResponder.apply(this, []);
}
internal.probes.push(this);
internal.probeAndAdvertise.apply(this, []);
};
Advertisement.prototype.stop = function () {
debug('unpublishing service');
internal.services =
internal.services.filter(function (service) { return service === this; });
if (!internal.haveResponder()) {
internal.stopResponder.apply(this, []);
}
internal.sendDNSPacket(pf.buildANPacket.apply(this, [0]));
this.nameSuffix = '';
this.alias = '';
this.status = 0; // inactive
};
var debug = require('debug')('mdns:browser');
var debugpacket = require('debug')('mdns:browser:packet');
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var dgram = require('dgram');
var os = require('os');
//var helper = require('../test/helper');
var dns = require('mdns-js-packet');

@@ -18,19 +16,2 @@ var DNSPacket = dns.DNSPacket;

var MDNS_MULTICAST = '224.0.0.251';
internal.broadcast = function (sock, serviceType) {
debug('broadcasting to', sock.address());
var packet = new DNSPacket();
packet.question.push(new DNSRecord(
serviceType.toString() + '.local',
DNSRecord.Type.PTR, 1)
);
var buf = DNSPacket.toBuffer(packet);
debug('created buffer with length', buf.length);
sock.send(buf, 0, buf.length, 5353, '224.0.0.251', function (err, bytes) {
debug('%s sent %d bytes with err:%s', sock.address().address, bytes, err);
});
};
/**

@@ -40,6 +21,6 @@ * Handles incoming UDP traffic.

*/
internal.onMessage = function (message, remote, connection) {
debug('got packet from remote', remote);
debugpacket('incomming packet', message.toString('hex'));
var data = decoder.decodeMessage(message);
internal.onMessage = function (packets, remote, connection) {
debug('got packets from remote', remote);
var data = decoder.decodePackets(packets);
var isNew = false;

@@ -138,3 +119,3 @@

*/
var Browser = module.exports = function (serviceType) {
var Browser = module.exports = function (networking, serviceType) {
if (!(this instanceof Browser)) { return new Browser(serviceType); }

@@ -152,129 +133,24 @@

var self = this;
this._all = new EventEmitter();
var services = {};
var addresses = {};
var connections = [];
var created = 0;
process.nextTick(function () {
var interfaces = os.networkInterfaces();
var index = 0;
for (var key in interfaces) {
if (interfaces.hasOwnProperty(key)) {
for (var i = 0; i < interfaces[key].length; i++) {
var iface = interfaces[key][i];
//no localhost
if (iface.internal) {
continue;
}
//no IPv6 addresses
if (iface.address.indexOf(':') !== -1) {
continue;
}
debug('interface', key, iface.address);
createSocket(index++, key,
iface.address, 0, bindToAddress.bind(self));
}
}
}
// var services = {};
// var addresses = {};
createSocket(index++, 'pseudo multicast',
'0.0.0.0', 5353, bindToAddress.bind(self));
}.bind(this));
networking.addUsage(this, function () {
self.emit('ready');
});
function createSocket(interfaceIndex, networkInterface, address, port, cb) {
var sock = dgram.createSocket('udp4');
debug('creating socket for interface %s', address);
created++;
sock.bind(port, address, function (err) {
if (port === 5353 && address === '0.0.0.0') {
sock.addMembership(MDNS_MULTICAST);
}
cb(err, interfaceIndex, networkInterface, sock);
});
}
function bindToAddress (err, interfaceIndex, networkInterface, sock) {
if (err) {
debug('there was an error binding %s', err);
return;
}
debug('bindToAddress');
var info = sock.address();
var connection = {
socket:sock,
hasTraffic: false,
interfaceIndex: interfaceIndex,
networkInterface: networkInterface,
services: services,
addresses: addresses
};
connections.push(connection);
sock.on('message', function () {
connection.hasTraffic = true;
[].push.call(arguments, connection);
internal.onMessage.apply(this, arguments);
}.bind(this));
sock.on('error', _onError);
sock.on('close', function () {
debug('socket closed', info);
});
self._all.on('broadcast', function () {
internal.broadcast(sock, serviceType);
}.bind(this));
if (created === connections.length) {
this.emit('ready', connections.length);
}
}//--bindToAddress
function _onError (err) {
debug('socket error', err);
self.emit('error', err);
}
this.stop = function () {
debug('stopping');
debug('connection.services', services);
debug('connection.addresses', addresses);
for (var i = 0; i < connections.length; i++) {
var socket = connections[i].socket;
socket.close();
socket.unref();
}
connections = [];
networking.removeUsage(this);
};//--start
networking.on('packets', internal.onMessage.bind(this));
this.discover = function () {
var packet = new DNSPacket();
packet.question.push(new DNSRecord(
serviceType.toString() + '.local',
DNSRecord.Type.PTR, 1)
);
networking.send(packet);
};
/**
* Close interfaces where no traffic have occured
*/
this.closeUnused = function () {
var i;
debug('closing sockets without traffic');
var closed = [];
for (i = 0; i < connections.length; i++) {
var connection = connections[i];
if (!connection.hasTraffic) {
connection.socket.close();
connection.socket.unref();
closed.push(connection);
}
}
for (i = 0; i < closed.length; i++) {
var index = connections.indexOf(closed[i]);
connections.splice(index, 1);
}
closed = [];
};//--closeUnused
};//--Browser constructor

@@ -284,18 +160,1 @@

// /**
// * Handles socket listen event
// * @private
// */
// Browser.prototype._onListening = function () {
// var address = this.sock.address();
// debug('Browser listening on %s:%s', address.address, address.port);
// };
Browser.prototype.discover = function () {
process.nextTick(function () {
debug('emitting broadcast request');
this._all.emit('broadcast');
}.bind(this));
};

@@ -75,2 +75,11 @@ var debug = require('debug')('mdns:lib:decoder');

module.exports.decodeMessage = function (message) {
var packets = dns.DNSPacket.parse(message);
if (!(packets instanceof Array)) {
packets = [packets];
}
return decodePackets(packets);
};
var decodePackets = module.exports.decodePackets = function (packets) {
var queryOnly = false;

@@ -80,6 +89,2 @@ var data = {

};
var packets = dns.DNSPacket.parse(message);
if (!(packets instanceof Array)) {
packets = [packets];
}
var query = [];

@@ -86,0 +91,0 @@ data.query = query;

{
"name": "mdns-js",
"version": "0.2.8",
"version": "0.2.9",
"repository": {

@@ -16,3 +16,3 @@ "type": "git",

"dependencies": {
"debug": "~0.8.1",
"debug": "^2.1.0",
"mdns-js-packet": "0.1.x"

@@ -22,6 +22,6 @@ },

"code": "^1.2.1",
"joi": "^4.8.1",
"joi": "^5.0.1",
"jscs": "^1.6.2",
"jshint": "*",
"lab": "^5.0.2"
"jshint": "^2.5.0",
"lab": "^5.1.0"
},

@@ -28,0 +28,0 @@ "scripts": {

@@ -20,4 +20,3 @@ var Lab = require('lab');

browser.on('ready', function onReady(socketcount) {
expect(socketcount).to.be.above(0);
browser.on('ready', function onReady() {
done();

@@ -44,7 +43,2 @@ });

it('should close unused', function (done) {
browser.closeUnused();
setTimeout(done, 500);
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc