summaryrefslogtreecommitdiff
path: root/root-watcher
diff options
context:
space:
mode:
Diffstat (limited to 'root-watcher')
-rw-r--r--root-watcher/README.md8
-rw-r--r--root-watcher/config.json.example30
-rw-r--r--root-watcher/package.json16
-rw-r--r--root-watcher/schema.sql21
-rw-r--r--root-watcher/zerotier-root-watcher.js235
5 files changed, 0 insertions, 310 deletions
diff --git a/root-watcher/README.md b/root-watcher/README.md
deleted file mode 100644
index ded6a63f..00000000
--- a/root-watcher/README.md
+++ /dev/null
@@ -1,8 +0,0 @@
-Root Server Watcher
-======
-
-This is a small daemon written in NodeJS that watches a set of root servers and records peer status information into a Postgres database.
-
-To use type `npm install` to install modules. Then edit `config.json.example` and rename to `config.json`. For each of your roots you will need to configure a way for this script to reach it. You will also need to use `schema.sql` to initialize a Postgres database to contain your logs and set it up in `config.json` as well.
-
-This doesn't (yet) include any software for reading the log database and doing anything useful with the information inside, though given that it's a simple SQL database it should not be hard to compose queries to show interesting statistics.
diff --git a/root-watcher/config.json.example b/root-watcher/config.json.example
deleted file mode 100644
index 0ad1bbe1..00000000
--- a/root-watcher/config.json.example
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "interval": 30000,
- "dbSaveInterval": 60000,
- "peerTimeout": 600000,
- "db": {
- "database": "ztr",
- "user": "postgres",
- "password": "s00p3rs3kr3t",
- "host": "127.0.0.1",
- "port": 5432,
- "max": 16,
- "idleTimeoutMillis": 30000
- },
- "roots": {
- "my-root-01": {
- "id": 1,
- "ip": "10.0.0.1",
- "port": 9993,
- "authToken": "foobarbaz",
- "peers": "/peer"
- },
- "my-root-02": {
- "id": 2,
- "ip": "10.0.0.2",
- "port": 9993,
- "authToken": "lalafoo",
- "peers": "/peer"
- }
- }
-}
diff --git a/root-watcher/package.json b/root-watcher/package.json
deleted file mode 100644
index d6e86d78..00000000
--- a/root-watcher/package.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "name": "zerotier-root-watcher",
- "version": "1.0.0",
- "description": "Simple background service to watch a cluster of roots and record peer info into a database",
- "main": "zerotier-root-watcher.js",
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
- },
- "author": "ZeroTier, Inc. <contact@zerotier.com>",
- "license": "GPL-3.0",
- "dependencies": {
- "async": "^2.3.0",
- "pg": "^6.1.5",
- "zlib": "^1.0.5"
- }
-}
diff --git a/root-watcher/schema.sql b/root-watcher/schema.sql
deleted file mode 100644
index bdb3a1cf..00000000
--- a/root-watcher/schema.sql
+++ /dev/null
@@ -1,21 +0,0 @@
-/* Schema for ZeroTier root watcher log database */
-
-/* If you cluster this DB using any PG clustering scheme that uses logs, you must remove UNLOGGED here! */
-CREATE UNLOGGED TABLE "Peer"
-(
- "ztAddress" BIGINT NOT NULL,
- "timestamp" BIGINT NOT NULL,
- "versionMajor" INTEGER NOT NULL,
- "versionMinor" INTEGER NOT NULL,
- "versionRev" INTEGER NOT NULL,
- "rootId" INTEGER NOT NULL,
- "phyPort" INTEGER NOT NULL,
- "phyLinkQuality" REAL NOT NULL,
- "phyLastReceive" BIGINT NOT NULL,
- "phyAddress" INET NOT NULL
-);
-
-CREATE INDEX "Peer_ztAddress" ON "Peer" ("ztAddress");
-CREATE INDEX "Peer_timestamp" ON "Peer" ("timestamp");
-CREATE INDEX "Peer_rootId" ON "Peer" ("rootId");
-CREATE INDEX "Peer_phyAddress" ON "Peer" ("phyAddress");
diff --git a/root-watcher/zerotier-root-watcher.js b/root-watcher/zerotier-root-watcher.js
deleted file mode 100644
index d4607fc2..00000000
--- a/root-watcher/zerotier-root-watcher.js
+++ /dev/null
@@ -1,235 +0,0 @@
-'use strict';
-
-const pg = require('pg');
-const zlib = require('zlib');
-const http = require('http');
-const fs = require('fs');
-const async = require('async');
-
-const config = JSON.parse(fs.readFileSync('./config.json'));
-const roots = config.roots||{};
-
-const db = new pg.Pool(config.db);
-
-process.on('uncaughtException',function(err) {
- console.error('ERROR: uncaught exception: '+err);
- if (err.stack)
- console.error(err.stack);
-});
-
-function httpRequest(host,port,authToken,method,path,args,callback)
-{
- var responseBody = [];
- var postData = (args) ? JSON.stringify(args) : null;
-
- var req = http.request({
- host: host,
- port: port,
- path: path,
- method: method,
- headers: {
- 'X-ZT1-Auth': (authToken||''),
- 'Content-Length': (postData) ? postData.length : 0
- }
- },function(res) {
- res.on('data',function(chunk) {
- if ((chunk)&&(chunk.length > 0))
- responseBody.push(chunk);
- });
- res.on('timeout',function() {
- try {
- if (typeof callback === 'function') {
- var cb = callback;
- callback = null;
- cb(new Error('connection timed out'),null);
- }
- req.abort();
- } catch (e) {}
- });
- res.on('error',function(e) {
- try {
- if (typeof callback === 'function') {
- var cb = callback;
- callback = null;
- cb(new Error('connection timed out'),null);
- }
- req.abort();
- } catch (e) {}
- });
- res.on('end',function() {
- if (typeof callback === 'function') {
- var cb = callback;
- callback = null;
- if (responseBody.length === 0) {
- return cb(null,{});
- } else {
- responseBody = Buffer.concat(responseBody);
-
- if (responseBody.length < 2) {
- return cb(null,{});
- }
-
- if ((responseBody.readUInt8(0,true) === 0x1f)&&(responseBody.readUInt8(1,true) === 0x8b)) {
- try {
- responseBody = zlib.gunzipSync(responseBody);
- } catch (e) {
- return cb(e,null);
- }
- }
-
- try {
- return cb(null,JSON.parse(responseBody));
- } catch (e) {
- return cb(e,null);
- }
- }
- }
- });
- }).on('error',function(e) {
- try {
- if (typeof callback === 'function') {
- var cb = callback;
- callback = null;
- cb(e,null);
- }
- req.abort();
- } catch (e) {}
- }).on('timeout',function() {
- try {
- if (typeof callback === 'function') {
- var cb = callback;
- callback = null;
- cb(new Error('connection timed out'),null);
- }
- req.abort();
- } catch (e) {}
- });
-
- req.setTimeout(30000);
- req.setNoDelay(true);
-
- if (postData !== null)
- req.end(postData);
- else req.end();
-};
-
-var peerStatus = {};
-
-function saveToDb()
-{
- db.connect(function(err,client,clientDone) {
- if (err) {
- console.log('WARNING: database error writing peers: '+err.toString());
- clientDone();
- return setTimeout(saveToDb,config.dbSaveInterval||60000);
- }
- client.query('BEGIN',function(err) {
- if (err) {
- console.log('WARNING: database error writing peers: '+err.toString());
- clientDone();
- return setTimeout(saveToDb,config.dbSaveInterval||60000);
- }
- let timeout = Date.now() - (config.peerTimeout||600000);
- let wtotal = 0;
- async.eachSeries(Object.keys(peerStatus),function(address,nextAddress) {
- let s = peerStatus[address];
- if (s[1] <= timeout) {
- delete peerStatus[address];
- return process.nextTick(nextAddress);
- } else {
- ++wtotal;
- client.query('INSERT INTO "Peer" ("ztAddress","timestamp","versionMajor","versionMinor","versionRev","rootId","phyPort","phyLinkQuality","phyLastReceive","phyAddress") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)',s,nextAddress);
- }
- },function(err) {
- if (err)
- console.log('WARNING database error writing peers: '+err.toString());
- console.log(Date.now().toString()+' '+wtotal);
- client.query('COMMIT',function(err,result) {
- clientDone();
- return setTimeout(saveToDb,config.dbSaveInterval||60000);
- });
- });
- });
- });
-};
-
-function doRootUpdate(name,id,ip,port,peersPath,authToken,interval)
-{
- httpRequest(ip,port,authToken,"GET",peersPath,null,function(err,res) {
- if (err) {
- console.log('WARNING: cannot reach '+name+peersPath+' (will try again in 1s): '+err.toString());
- return setTimeout(function() { doRootUpdate(name,id,ip,port,peersPath,authToken,interval); },1000);
- }
- if (!Array.isArray(res)) {
- console.log('WARNING: cannot reach '+name+peersPath+' (will try again in 1s): response is not an array of peers');
- return setTimeout(function() { doRootUpdate(name,id,ip,port,peersPath,authToken,interval); },1000);
- }
-
- //console.log(name+': '+res.length+' peer entries.');
- let now = Date.now();
- let count = 0;
- for(let pi=0;pi<res.length;++pi) {
- let peer = res[pi];
- let address = peer.address;
- let ztAddress = parseInt(address,16)||0;
- if (!ztAddress)
- continue;
-
- let paths = peer.paths;
- if ((Array.isArray(paths))&&(paths.length > 0)) {
- let bestPath = null;
- for(let i=0;i<paths.length;++i) {
- if (paths[i].active) {
- let lr = paths[i].lastReceive;
- if ((lr > 0)&&((!bestPath)||(bestPath.lastReceive < lr)))
- bestPath = paths[i];
- }
- }
-
- if (bestPath) {
- let a = bestPath.address;
- if (typeof a === 'string') {
- let a2 = a.split('/');
- if (a2.length === 2) {
- let vmaj = peer.versionMajor;
- if ((typeof vmaj === 'undefined')||(vmaj === null)) vmaj = -1;
- let vmin = peer.versionMinor;
- if ((typeof vmin === 'undefined')||(vmin === null)) vmin = -1;
- let vrev = peer.versionRev;
- if ((typeof vrev === 'undefined')||(vrev === null)) vrev = -1;
- let lr = parseInt(bestPath.lastReceive)||0;
-
- let s = peerStatus[address];
- if ((!s)||(s[8] < lr)) {
- peerStatus[address] = [
- ztAddress,
- now,
- vmaj,
- vmin,
- vrev,
- id,
- parseInt(a2[1])||0,
- parseFloat(bestPath.linkQuality)||1.0,
- lr,
- a2[0]
- ];
- }
- ++count;
- }
- }
- }
- }
- }
-
- console.log(name+': '+count+' peers with active direct paths.');
- return setTimeout(function() { doRootUpdate(name,id,ip,port,peersPath,authToken,interval); },interval);
- });
-};
-
-for(var r in roots) {
- var rr = roots[r];
- if (rr.peers)
- doRootUpdate(r,rr.id,rr.ip,rr.port,rr.peers,rr.authToken||null,config.interval||60000);
-}
-
-return setTimeout(saveToDb,config.dbSaveInterval||60000);