1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/app.js Tue Aug 12 18:32:40 2014 +0200 1.3 @@ -0,0 +1,166 @@ 1.4 +#! /usr/bin/env nodejs 1.5 +// 1.6 +// mDNSGw - Zero Configuration DNS Gateway for Mesh Networks 1.7 +// Copyright © 2014 Michael Schloh von Bennewitz <michael@schloh.com> 1.8 +// 1.9 +// Permission to use, copy, modify, and/or distribute this software for 1.10 +// any purpose with or without fee is hereby granted, provided that the 1.11 +// above copyright notice and this permission notice appear in all copies. 1.12 +// 1.13 +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 1.14 +// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 1.15 +// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 1.16 +// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 1.17 +// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 1.18 +// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 1.19 +// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 1.20 +// THIS SOFTWARE. 1.21 +// 1.22 +// This file is part of mDNSGw, a Zero configuration DNS gateway 1.23 +// which can be found at http://dev.europalab.com/mdnsgw/ 1.24 +// 1.25 +// app.js: ECMA JavaScript implementation 1.26 +// 1.27 + 1.28 +/*********************************************************** 1.29 +| ____ _ _ ____ ____ | 1.30 +| _ __ ___ | _ \| \ | / ___| / ___|_ __ | 1.31 +| | '_ ` _ \| | | | \| \___ \| | _\ \ /\ / / | 1.32 +| | | | | | | |_| | |\ |___) | |_| |\ V V / | 1.33 +| |_| |_| |_|____/|_| \_|____/ \____| \_/\_/ | 1.34 +| | 1.35 +| Requirements: Redis server with standard configuration | 1.36 +| NodeJS and NPM modules (see package.json) | 1.37 +| | 1.38 +| Execute: To start this application, launch it with the | 1.39 +| script named fork.js: $ ./fork.js | 1.40 +| | 1.41 +| Support: http://list.europalab.com/mailman/mdnsgs/ | 1.42 +| | 1.43 +***********************************************************/ 1.44 + 1.45 +// import module dependencies 1.46 +var mdnsinst = require('mdns'); 1.47 +var redisdat = require('redis'); 1.48 +var nameinst = require('native-dns'); 1.49 + 1.50 + 1.51 +// instantiate a new redis client 1.52 +// http://www.rediscookbook.org/ 1.53 +var rediscli = redisdat.createClient(); 1.54 +rediscli.on('error', function (error) { 1.55 + console.log('Error ' + error); 1.56 +}); 1.57 + 1.58 +// clear mDNS service keys 1.59 +rediscli.del('hostnames'); 1.60 +// this is not working unfortunately for the loop 1.61 +rediscli.keys('*', function (error, replies) { 1.62 + replies.forEach(function (reply, ident) { 1.63 + rediscli.del(reply, function (error, value) { 1.64 + if (error) throw(error); 1.65 + }); 1.66 + }); 1.67 +}); 1.68 + 1.69 +// scan all advertised mDNS service types 1.70 +var browsall = mdnsinst.browseThemAll(); 1.71 +browsall.on('serviceUp', function(service) { 1.72 + // iterate through hosts and watch accordingly 1.73 + if (service.type.name.match(/^[a-zA-Z0-9\-]+$/)) { // mdns module hack 1.74 + if (service.type.protocol == 'tcp') { 1.75 + var browserv = mdnsinst.createBrowser(mdnsinst.tcp(service.type.name)); 1.76 + } 1.77 + else if (service.type.protocol == 'udp') { 1.78 + var browserv = mdnsinst.createBrowser(mdnsinst.udp(service.type.name)); 1.79 + } 1.80 + else if (service.type.protocol == 'sctp') { 1.81 + var browserv = mdnsinst.createBrowser(mdnsinst.sctp(service.type.name)); 1.82 + } 1.83 + else throw(error); 1.84 + 1.85 + // common logic for all transports (TCP, UDP, SCTP, etcetera) 1.86 + browserv.on('serviceUp', function(service) { 1.87 + //console.log('service up: ', service); 1.88 + //{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']} 1.89 + 1.90 + // insert one or more IP addresses for each hostname.local. 1.91 + rediscli.hset('hostnames', service.host.replace(/\.$/, ''), service.addresses); 1.92 + }); 1.93 + browserv.on('serviceDown', function(service) { 1.94 + //console.log('service down: ', service); 1.95 + //FIXME: still need to selectively remove hosts 1.96 + }); 1.97 + browserv.start(); 1.98 + } 1.99 +}); 1.100 +browsall.start(); 1.101 + 1.102 +// instantiate a new DNS server 1.103 +var nameserv = nameinst.createServer(); 1.104 + 1.105 +nameserv.on('request', function (request, response) { 1.106 + //console.log(request) 1.107 + 1.108 + // ensure that requested hostname is present 1.109 + rediscli.hget('hostnames', request.question[0].name, function (error, value) { 1.110 + // handle unexpected errors 1.111 + if (error) throw(error); 1.112 + 1.113 + if (value) { // the db succeeded in finding a match 1.114 + // populate the DNS response with the chosen hostname 1.115 + rediscli.hkeys('hostnames', function (error, replies) { 1.116 + replies.forEach(function (host, index) { 1.117 + if (request.question[0].name == host) { 1.118 + rediscli.hget('hostnames', host, function (error, value) { 1.119 + // handle unexpected errors 1.120 + if (error) throw(error); 1.121 + 1.122 + // FIXME: still must handle multihomed hosts 1.123 + //// a host might have more than one address 1.124 + //value.forEach(function (addr, iter) 1.125 + // set the nameserver address 1.126 + response.answer.push(nameinst.A({ 1.127 + name: host, 1.128 + address: value, 1.129 + ttl: 600, 1.130 + })); 1.131 + response.send(); 1.132 + }); 1.133 + } 1.134 + }); 1.135 + }); 1.136 + } 1.137 + else { 1.138 + response.answer.push(nameinst.A({ 1.139 + name: request.question[0].name, 1.140 + address: '127.0.0.1', 1.141 + ttl: 600, 1.142 + })); 1.143 + response.send(); 1.144 + } 1.145 + }); 1.146 +}); 1.147 + 1.148 +// DNS error handler logic 1.149 +nameserv.on('error', function (err, buff, req, res) { 1.150 + console.log('DNS problem: ', err.stack); 1.151 +}); 1.152 + 1.153 +nameserv.serve(15353); 1.154 + 1.155 +//// debug print all key and value database entries 1.156 +//rediscli.hgetall('hostnames', function (error, object) {console.dir(object);}); 1.157 + 1.158 +//// display stored mDNS service data entries 1.159 +//rediscli.hkeys('hostnames', function (error, replies) { 1.160 +// console.log(replies.length + ' replies:'); 1.161 +// replies.forEach(function (reply, ident) { 1.162 +// console.log(' ' + ident + ': ' + reply); 1.163 +// }); 1.164 +//}); 1.165 + 1.166 +//// block executes on program termination 1.167 +//rediscli.quit(); // cleanup db connection 1.168 +//browserv.stop(); // zombie scope too bad 1.169 +//browsall.stop();