src/app.js

changeset 0
eb6d4ce6fd78
child 3
42e83b3431d9
     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();

mercurial