Wed, 13 Aug 2014 20:55:48 +0200
Make general improvements to the package specification.
1 #! /usr/bin/env nodejs
2 //
3 // mDNSGw - Zero Configuration DNS Gateway for Mesh Networks
4 // Copyright © 2014 Michael Schloh von Bennewitz <michael@schloh.com>
5 //
6 // Permission to use, copy, modify, and/or distribute this software for
7 // any purpose with or without fee is hereby granted, provided that the
8 // above copyright notice and this permission notice appear in all copies.
9 //
10 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 // WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 // WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 // AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 // DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 // PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
16 // ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
17 // THIS SOFTWARE.
18 //
19 // This file is part of mDNSGw, a Zero configuration DNS gateway
20 // which can be found at http://dev.europalab.com/mdnsgw/
21 //
22 // app.js: ECMA JavaScript implementation
23 //
25 /***********************************************************
26 | ____ _ _ ____ ____ |
27 | _ __ ___ | _ \| \ | / ___| / ___|_ __ |
28 | | '_ ` _ \| | | | \| \___ \| | _\ \ /\ / / |
29 | | | | | | | |_| | |\ |___) | |_| |\ V V / |
30 | |_| |_| |_|____/|_| \_|____/ \____| \_/\_/ |
31 | |
32 | Requirements: Redis server with standard configuration |
33 | NodeJS and NPM modules (see package.json) |
34 | |
35 | Execute: To start this application, launch it with the |
36 | script named fork.js: $ ./fork.js |
37 | |
38 | Support: http://list.europalab.com/mailman/mdnsgs/ |
39 | |
40 ***********************************************************/
42 // import module dependencies
43 var mdnsinst = require('mdns');
44 var redisdat = require('redis');
45 var nameinst = require('native-dns');
48 // instantiate a new redis client
49 // http://www.rediscookbook.org/
50 var rediscli = redisdat.createClient();
51 rediscli.on('error', function (error) {
52 console.log('Error ' + error);
53 });
55 // clear mDNS service keys
56 rediscli.del('hostnames');
57 // this is not working unfortunately for the loop
58 rediscli.keys('*', function (error, replies) {
59 replies.forEach(function (reply, ident) {
60 rediscli.del(reply, function (error, value) {
61 if (error) throw(error);
62 });
63 });
64 });
66 // scan all advertised mDNS service types
67 var browsall = mdnsinst.browseThemAll();
68 browsall.on('serviceUp', function(service) {
69 // iterate through hosts and watch accordingly
70 if (service.type.name.match(/^[a-zA-Z0-9\-]+$/)) { // mdns module hack
71 if (service.type.protocol == 'tcp') {
72 var browserv = mdnsinst.createBrowser(mdnsinst.tcp(service.type.name));
73 }
74 else if (service.type.protocol == 'udp') {
75 var browserv = mdnsinst.createBrowser(mdnsinst.udp(service.type.name));
76 }
77 else if (service.type.protocol == 'sctp') {
78 var browserv = mdnsinst.createBrowser(mdnsinst.sctp(service.type.name));
79 }
80 else throw(error);
82 // common logic for all transports (TCP, UDP, SCTP, etcetera)
83 browserv.on('serviceUp', function(service) {
84 //console.log('service up: ', service);
85 //{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']}
87 // insert one or more IP addresses for each hostname.local.
88 rediscli.hset('hostnames', service.host.replace(/\.$/, ''), service.addresses);
89 });
90 browserv.on('serviceDown', function(service) {
91 //console.log('service down: ', service);
92 //FIXME: still need to selectively remove hosts
93 });
94 browserv.start();
95 }
96 });
97 browsall.start();
99 // instantiate a new DNS server
100 var nameserv = nameinst.createServer();
102 nameserv.on('request', function (request, response) {
103 //console.log(request)
105 // ensure that requested hostname is present
106 rediscli.hget('hostnames', request.question[0].name, function (error, value) {
107 // handle unexpected errors
108 if (error) throw(error);
110 if (value) { // the db succeeded in finding a match
111 // populate the DNS response with the chosen hostname
112 rediscli.hkeys('hostnames', function (error, replies) {
113 replies.forEach(function (host, index) {
114 if (request.question[0].name == host) {
115 rediscli.hget('hostnames', host, function (error, value) {
116 // handle unexpected errors
117 if (error) throw(error);
119 // FIXME: still must handle multihomed hosts
120 //// a host might have more than one address
121 //value.forEach(function (addr, iter)
122 // set the nameserver address
123 response.answer.push(nameinst.A({
124 name: host,
125 address: value,
126 ttl: 600,
127 }));
128 response.send();
129 });
130 }
131 });
132 });
133 }
134 else {
135 response.answer.push(nameinst.A({
136 name: request.question[0].name,
137 address: '127.0.0.1',
138 ttl: 600,
139 }));
140 response.send();
141 }
142 });
143 });
145 // DNS error handler logic
146 nameserv.on('error', function (err, buff, req, res) {
147 console.log('DNS problem: ', err.stack);
148 });
150 nameserv.serve(15353);
152 //// debug print all key and value database entries
153 //rediscli.hgetall('hostnames', function (error, object) {console.dir(object);});
155 //// display stored mDNS service data entries
156 //rediscli.hkeys('hostnames', function (error, replies) {
157 // console.log(replies.length + ' replies:');
158 // replies.forEach(function (reply, ident) {
159 // console.log(' ' + ident + ': ' + reply);
160 // });
161 //});
163 //// block executes on program termination
164 //rediscli.quit(); // cleanup db connection
165 //browserv.stop(); // zombie scope too bad
166 //browsall.stop();