|
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 // |
|
24 |
|
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 ***********************************************************/ |
|
41 |
|
42 // import module dependencies |
|
43 var mdnsinst = require('mdns'); |
|
44 var redisdat = require('redis'); |
|
45 var nameinst = require('native-dns'); |
|
46 |
|
47 |
|
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 }); |
|
54 |
|
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 }); |
|
65 |
|
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); |
|
81 |
|
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']} |
|
86 |
|
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(); |
|
98 |
|
99 // instantiate a new DNS server |
|
100 var nameserv = nameinst.createServer(); |
|
101 |
|
102 nameserv.on('request', function (request, response) { |
|
103 //console.log(request) |
|
104 |
|
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); |
|
109 |
|
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); |
|
118 |
|
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 }); |
|
144 |
|
145 // DNS error handler logic |
|
146 nameserv.on('error', function (err, buff, req, res) { |
|
147 console.log('DNS problem: ', err.stack); |
|
148 }); |
|
149 |
|
150 nameserv.serve(15353); |
|
151 |
|
152 //// debug print all key and value database entries |
|
153 //rediscli.hgetall('hostnames', function (error, object) {console.dir(object);}); |
|
154 |
|
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 //}); |
|
162 |
|
163 //// block executes on program termination |
|
164 //rediscli.quit(); // cleanup db connection |
|
165 //browserv.stop(); // zombie scope too bad |
|
166 //browsall.stop(); |