diff -r 000000000000 -r eb6d4ce6fd78 src/app.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app.js Tue Aug 12 18:32:40 2014 +0200 @@ -0,0 +1,166 @@ +#! /usr/bin/env nodejs +// +// mDNSGw - Zero Configuration DNS Gateway for Mesh Networks +// Copyright © 2014 Michael Schloh von Bennewitz +// +// Permission to use, copy, modify, and/or distribute this software for +// any purpose with or without fee is hereby granted, provided that the +// above copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +// THIS SOFTWARE. +// +// This file is part of mDNSGw, a Zero configuration DNS gateway +// which can be found at http://dev.europalab.com/mdnsgw/ +// +// app.js: ECMA JavaScript implementation +// + +/*********************************************************** +| ____ _ _ ____ ____ | +| _ __ ___ | _ \| \ | / ___| / ___|_ __ | +| | '_ ` _ \| | | | \| \___ \| | _\ \ /\ / / | +| | | | | | | |_| | |\ |___) | |_| |\ V V / | +| |_| |_| |_|____/|_| \_|____/ \____| \_/\_/ | +| | +| Requirements: Redis server with standard configuration | +| NodeJS and NPM modules (see package.json) | +| | +| Execute: To start this application, launch it with the | +| script named fork.js: $ ./fork.js | +| | +| Support: http://list.europalab.com/mailman/mdnsgs/ | +| | +***********************************************************/ + +// import module dependencies +var mdnsinst = require('mdns'); +var redisdat = require('redis'); +var nameinst = require('native-dns'); + + +// instantiate a new redis client +// http://www.rediscookbook.org/ +var rediscli = redisdat.createClient(); +rediscli.on('error', function (error) { + console.log('Error ' + error); +}); + +// clear mDNS service keys +rediscli.del('hostnames'); +// this is not working unfortunately for the loop +rediscli.keys('*', function (error, replies) { + replies.forEach(function (reply, ident) { + rediscli.del(reply, function (error, value) { + if (error) throw(error); + }); + }); +}); + +// scan all advertised mDNS service types +var browsall = mdnsinst.browseThemAll(); +browsall.on('serviceUp', function(service) { + // iterate through hosts and watch accordingly + if (service.type.name.match(/^[a-zA-Z0-9\-]+$/)) { // mdns module hack + if (service.type.protocol == 'tcp') { + var browserv = mdnsinst.createBrowser(mdnsinst.tcp(service.type.name)); + } + else if (service.type.protocol == 'udp') { + var browserv = mdnsinst.createBrowser(mdnsinst.udp(service.type.name)); + } + else if (service.type.protocol == 'sctp') { + var browserv = mdnsinst.createBrowser(mdnsinst.sctp(service.type.name)); + } + else throw(error); + + // common logic for all transports (TCP, UDP, SCTP, etcetera) + browserv.on('serviceUp', function(service) { + //console.log('service up: ', service); + //{interfaceIndex: 2, type: {name: 'ssh', protocol: 'tcp', subtypes: [], fullyQualified: true}, replyDomain: 'local.', flags: 2, name: 'hostname-mich', networkInterface: 'eth0', fullname: 'hostname-mich._ssh._tcp.local.', host: 'hostname-mich.local.', port: 22, addresses: ['192.168.1.50']} + + // insert one or more IP addresses for each hostname.local. + rediscli.hset('hostnames', service.host.replace(/\.$/, ''), service.addresses); + }); + browserv.on('serviceDown', function(service) { + //console.log('service down: ', service); + //FIXME: still need to selectively remove hosts + }); + browserv.start(); + } +}); +browsall.start(); + +// instantiate a new DNS server +var nameserv = nameinst.createServer(); + +nameserv.on('request', function (request, response) { + //console.log(request) + + // ensure that requested hostname is present + rediscli.hget('hostnames', request.question[0].name, function (error, value) { + // handle unexpected errors + if (error) throw(error); + + if (value) { // the db succeeded in finding a match + // populate the DNS response with the chosen hostname + rediscli.hkeys('hostnames', function (error, replies) { + replies.forEach(function (host, index) { + if (request.question[0].name == host) { + rediscli.hget('hostnames', host, function (error, value) { + // handle unexpected errors + if (error) throw(error); + + // FIXME: still must handle multihomed hosts + //// a host might have more than one address + //value.forEach(function (addr, iter) + // set the nameserver address + response.answer.push(nameinst.A({ + name: host, + address: value, + ttl: 600, + })); + response.send(); + }); + } + }); + }); + } + else { + response.answer.push(nameinst.A({ + name: request.question[0].name, + address: '127.0.0.1', + ttl: 600, + })); + response.send(); + } + }); +}); + +// DNS error handler logic +nameserv.on('error', function (err, buff, req, res) { + console.log('DNS problem: ', err.stack); +}); + +nameserv.serve(15353); + +//// debug print all key and value database entries +//rediscli.hgetall('hostnames', function (error, object) {console.dir(object);}); + +//// display stored mDNS service data entries +//rediscli.hkeys('hostnames', function (error, replies) { +// console.log(replies.length + ' replies:'); +// replies.forEach(function (reply, ident) { +// console.log(' ' + ident + ': ' + reply); +// }); +//}); + +//// block executes on program termination +//rediscli.quit(); // cleanup db connection +//browserv.stop(); // zombie scope too bad +//browsall.stop();