Add main.js
This commit is contained in:
commit
0650417d93
148
main.js
Normal file
148
main.js
Normal file
@ -0,0 +1,148 @@
|
||||
// mdns-sync.js
|
||||
// A single-file mDNS sync tool acting as client or server
|
||||
// Uses mdns-server for mDNS and Express for HTTP
|
||||
|
||||
|
||||
/*********************************
|
||||
*
|
||||
* 1. LIBRARY FUNCTIONS
|
||||
*
|
||||
*********************************/
|
||||
|
||||
// 0. HELPER FUNCTIONS
|
||||
function convertBufferToString(a) {if (a.data) for (i in a.data) a.data[i] = a.data[i].toString(); return a;}
|
||||
|
||||
// 1. Database functions
|
||||
function saveDbToFile(data, filename) {return fs.writeFileSync(filename,typeof data === 'object'?JSON.stringify(data):data);}
|
||||
function loadDbFromFile(filename) {if (!fs.existsSync(filename)) return {local:{},remote:{}}; else return JSON.parse(fs.readFileSync(filename));}
|
||||
|
||||
// 2. Network functions
|
||||
function getLocalNetworkAddressesIPs() {
|
||||
const os = require('os');
|
||||
|
||||
const interfaces = os.networkInterfaces();
|
||||
const addresses = [];
|
||||
|
||||
for (const name of Object.keys(interfaces)) {
|
||||
for (const iface of interfaces[name]) {
|
||||
if (iface.family === 'IPv4' && !iface.internal) {
|
||||
addresses.push(iface.address);
|
||||
}
|
||||
}
|
||||
}
|
||||
return addresses;
|
||||
|
||||
}
|
||||
|
||||
function sniffmDNSLocalPackets() {
|
||||
|
||||
// 1. Listen for responses
|
||||
mdns.on('response', function(response) {
|
||||
// console.log("got a new mDNS response.",response);
|
||||
for (k in response.answers) {
|
||||
let answer = response.answers[k];
|
||||
|
||||
// 1. Handle DEVICES for a given SERVICE
|
||||
if (answer.type == "PTR") {
|
||||
// 1.1 Filter by RELEVANT SERVICE TYPES
|
||||
if (!["in-addr.arpa","_googlecast._tcp.local","_tcp.local"].some(suffix => answer.name.endsWith(suffix))) return;
|
||||
|
||||
// 1.2 Initialize POINTERS (services) sub-database
|
||||
if (!db.local.PTR) db.local.PTR = {};
|
||||
|
||||
// 1.3 Initialize this SERVICE TYPE (e.g. _googlecast._tcp.local), if needed
|
||||
if (!db.local.PTR[answer.name]) {
|
||||
db.local.PTR[answer.name] = [answer.data];
|
||||
} else {
|
||||
// Add a new DEVICE to this SERVICE TYPE if needed
|
||||
if (!db.local.PTR[answer.name].includes(answer.data))
|
||||
db.local.PTR[answer.name].push(answer.data);
|
||||
}
|
||||
}
|
||||
// 2. Handle DEVICE IP resolution
|
||||
if (answer.type == "A") {
|
||||
// 2.1 Initialize ADDRESSES sub-database
|
||||
if (!db.local.A) db.local.A = {};
|
||||
db.local.A[answer.name] = answer.data;
|
||||
}
|
||||
|
||||
if (["TXT","SRV"].includes(answer.type)) {
|
||||
// Initialize this device / entry, if needed
|
||||
if (db.local[answer.name] === undefined) db.local[answer.name] = {"TXT":null,"SRV":null};
|
||||
|
||||
db.local[answer.name][answer.type] = answer.data;
|
||||
}
|
||||
saveDbToFile(db,DB_FILENAME);
|
||||
}
|
||||
})
|
||||
|
||||
// 2. Listen for queries
|
||||
mdns.on('query', function(query) {/* console.log("query requested",query);*/});
|
||||
|
||||
// 3. Handle the server being destroyed
|
||||
mdns.on('destroyed', function () {console.log('Server destroyed.');process.exit(0);});
|
||||
|
||||
// 4. Handle the onReady event
|
||||
mdns.on('ready', function () {
|
||||
|
||||
console.log("mDNS server is ready...");
|
||||
// mdns.query({questions:[{ name: '_:googlecast._tcp.local', type: 'PTR', class: 'IN'}]} );
|
||||
})
|
||||
|
||||
// initialize the server now that we are watching for events
|
||||
mdns.initServer()
|
||||
|
||||
}
|
||||
function injectmDNSPacketLocally(type,name,data,flush = true,_class = 'IN',ttl = 120) {
|
||||
console.log(`sending packet ${name} of ${type} with data: ${data}`);
|
||||
mdns.respond({answers:[
|
||||
{
|
||||
name: name,
|
||||
type: type,
|
||||
ttl: ttl,
|
||||
class: _class,
|
||||
flush: flush,
|
||||
data: data
|
||||
}
|
||||
]});}
|
||||
|
||||
|
||||
|
||||
/*********************************
|
||||
*
|
||||
* 100. MAIN / IMPERATIVE CODE
|
||||
*
|
||||
*********************************/
|
||||
|
||||
const fs = require("fs");
|
||||
const DB_FILENAME = 'database.json';
|
||||
const db = loadDbFromFile(DB_FILENAME);
|
||||
const LOCAL_IP_ADDR = getLocalNetworkAddressesIPs()[0];
|
||||
const mdns = require('mdns-server')({interface: LOCAL_IP_ADDR,reuseAddr: true,loopback: false,noInit: true});
|
||||
sniffmDNSLocalPackets();
|
||||
|
||||
setInterval(function(){
|
||||
// INJECT PTR - Pointers services
|
||||
for (name in db.remote.PTR) {
|
||||
for (i in db.remote.PTR[name])
|
||||
injectmDNSPacketLocally('PTR',name,db.remote.PTR[name][i]);
|
||||
}
|
||||
// INJECT A - Addresses
|
||||
for (name in db.remote.A) {
|
||||
injectmDNSPacketLocally('A',name,db.remote.A[name]);
|
||||
}
|
||||
|
||||
|
||||
// INJECT SRV,TXT
|
||||
for (name in db.remote) {
|
||||
if (["PTR","A"].includes(name)) continue;
|
||||
if (db.remote[name].SRV !== null)
|
||||
injectmDNSPacketLocally('SRV',name,db.remote[name].SRV);
|
||||
if (db.remote[name].TXT !== null)
|
||||
injectmDNSPacketLocally('TXT',name,Buffer.from(db.remote[name].TXT, 'utf8'));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
},5000);
|
||||
Loading…
x
Reference in New Issue
Block a user