# HG changeset patch # User Michael Schloh von Bennewitz # Date 1407956523 -7200 # Node ID ee8de27ff2648f6a5f68cba71a205f92769a7209 # Parent 3de96d11e41721f420ff3c21c2ebedcd511bf7d0 Improve project layout and abstract library from program logic. diff -r 3de96d11e417 -r ee8de27ff264 src/app.js --- a/src/app.js Wed Aug 13 21:01:00 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,212 +0,0 @@ -#! /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'); - - -// install POSIX signal handlers -process.on('SIGUSR2', function() { - console.log('SIGUSR2: Dumping mDNSGw entries at', Date()); - rediscli.hgetall('hostnames', function (error, object) {console.dir(object);}); -}); -process.on('SIGHUP', function() { - console.log('SIGHUP: Cleared all database entries at', Date()); - cleardb(); -}); - -// 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 -function cleardb () { - 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 -cleardb(); // clear old data first -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.on('serviceChanged', function(service) { - console.log('service changed: ', service); - //FIXME: still need to selectively update 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); -}); - -//// debug process user -//console.log('Start.'); -//console.log(process.env.USER); -//console.log(process.env.SUDO_USER); -//console.log('Done.'); -// -// <1024 must run privileged -var nudpport = 53; // default DNS -if (nudpport < 1024 && process.getuid() !== 0) { - //console.log('Serving on port <1024 from an unprivileged user.\nChange to root if using a privileged port number.') - throw new Error('Serving on port <1024 from an unprivileged user.') -} - -// start the DNS process -nameserv.serve(nudpport, function () { - try { - console.log('Starting mDNSGw on', Date()); - process.stdout.write('Old UID: ' + process.getuid() + ', Old GID: ' + process.getgid() + '... '); - process.umask('0644'); - process.setgid('daemon'); - if (process.env.SUDO_USER) - process.setuid(process.env.SUDO_USER); - else - process.setuid('daemon'); - console.log('New UID: ' + process.getuid() + ', New GID: ' + process.getgid()); - } catch (err) { - console.log('Cowardly refusing to keep the process alive as root.'); - process.exit(1); - } -}); - -//// 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(); diff -r 3de96d11e417 -r ee8de27ff264 src/bin/fork.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/bin/fork.js Wed Aug 13 21:02:03 2014 +0200 @@ -0,0 +1,66 @@ +#! /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/ +// +// fork.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 forkserv = require('forever-monitor'); + + +// configure a child process to daemonize +var childproc = new (forkserv.Monitor)('app.js', { + max: 4, + silent: true, + pidFile: '/tmp/mdnsgw.pid', + logFile: '/tmp/mdnsgw.log', + outFile: '/tmp/mdnsgw.out', + errFile: '/tmp/mdnsgw.err', + options: [] +}); + +childproc.on('exit', function () { + console.log('app.js has exited after 4 restarts'); +}); + +// fork a child +childproc.start(); + +//// daemonize by exit +//that doesn't work +//process.exit(0); diff -r 3de96d11e417 -r ee8de27ff264 src/fork.js --- a/src/fork.js Wed Aug 13 21:01:00 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -#! /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/ -// -// fork.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 forkserv = require('forever-monitor'); - - -// configure a child process to daemonize -var childproc = new (forkserv.Monitor)('app.js', { - max: 4, - silent: true, - pidFile: '/tmp/mdnsgw.pid', - logFile: '/tmp/mdnsgw.log', - outFile: '/tmp/mdnsgw.out', - errFile: '/tmp/mdnsgw.err', - options: [] -}); - -childproc.on('exit', function () { - console.log('app.js has exited after 4 restarts'); -}); - -// fork a child -childproc.start(); - -//// daemonize by exit -//that doesn't work -//process.exit(0); diff -r 3de96d11e417 -r ee8de27ff264 src/lib/app.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/app.js Wed Aug 13 21:02:03 2014 +0200 @@ -0,0 +1,212 @@ +#! /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'); + + +// install POSIX signal handlers +process.on('SIGUSR2', function() { + console.log('SIGUSR2: Dumping mDNSGw entries at', Date()); + rediscli.hgetall('hostnames', function (error, object) {console.dir(object);}); +}); +process.on('SIGHUP', function() { + console.log('SIGHUP: Cleared all database entries at', Date()); + cleardb(); +}); + +// 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 +function cleardb () { + 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 +cleardb(); // clear old data first +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.on('serviceChanged', function(service) { + console.log('service changed: ', service); + //FIXME: still need to selectively update 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); +}); + +//// debug process user +//console.log('Start.'); +//console.log(process.env.USER); +//console.log(process.env.SUDO_USER); +//console.log('Done.'); +// +// <1024 must run privileged +var nudpport = 53; // default DNS +if (nudpport < 1024 && process.getuid() !== 0) { + //console.log('Serving on port <1024 from an unprivileged user.\nChange to root if using a privileged port number.') + throw new Error('Serving on port <1024 from an unprivileged user.') +} + +// start the DNS process +nameserv.serve(nudpport, function () { + try { + console.log('Starting mDNSGw on', Date()); + process.stdout.write('Old UID: ' + process.getuid() + ', Old GID: ' + process.getgid() + '... '); + process.umask('0644'); + process.setgid('daemon'); + if (process.env.SUDO_USER) + process.setuid(process.env.SUDO_USER); + else + process.setuid('daemon'); + console.log('New UID: ' + process.getuid() + ', New GID: ' + process.getgid()); + } catch (err) { + console.log('Cowardly refusing to keep the process alive as root.'); + process.exit(1); + } +}); + +//// 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();