#!/usr/bin/env node /* -*- Mode:js */ /* vim: set expandtab ts=4 sw=4: */ /* * You may redistribute this program and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ var Cjdns = require('./lib/cjdnsadmin/cjdnsadmin'); var nThen = require('nthen'); var PubToIp6 = require('./lib/publicToIp6'); var Dns = require('dns'); var IP6_REGEX = new RegExp('^' + new Array(9).join(':[0-9a-f]{1,4}').substring(1) + '$'); var LABEL_REGEX = new RegExp('^' + new Array(5).join('.[0-9a-f]{4}').substring(1) + '$'); var ADDR_REGEX = new RegExp('^v[0-9]+' + new Array(5).join('\\.[0-9a-f]{4}') + '\\.[a-z0-9]{52}\\.k$'); var validTarget = function (target) { if (IP6_REGEX.test(target)) { return true; } if (LABEL_REGEX.test(target)) { return true; } if (ADDR_REGEX.test(target)) { return true; } return false; }; var nodeToIP6 = function (nodeDesc) { var key = nodeDesc.replace(/.*\.([^.]*\.k)$/, function (all, one) { return one; }); return PubToIp6.convert(key); }; var highBits = function (nodeDesc) { var ip6 = nodeToIP6(nodeDesc); return ip6.substring(20,29); } var tracePath = function (target, queryNode, cjdns, cb, doneCb) { var lastNode = queryNode; var again = function () { cjdns.RouterModule_nextHop(target, lastNode, function (err, ret) { if (err) { throw err; } ret.from = lastNode; ret.fromIP6 = nodeToIP6(lastNode); cb(ret); if (ret.error !== 'none' || !ret.nodes || !ret.nodes.length) { doneCb(false); return; } if (ret.fromIP6 === target || ret.from === ret.nodes[0]) { doneCb(true); return; } lastNode = ret.nodes[0]; again(); }); }; again(); }; var main = function (target) { var cjdns; var self; var lastRet; nThen(function (waitFor) { Cjdns.connectWithAdminInfo(waitFor(function (c) { cjdns = c; })); if (!validTarget(target)) { Dns.lookup(target, 6, waitFor(function (err, res) { if (err) { throw err; } console.log(target + ' has ip address ' + res); target = res; })); } }).nThen(function (waitFor) { cjdns.RouterModule_getPeers("0000.0000.0000.0001", waitFor(function (err, ret) { if (err) { throw err; } self = ret.peers[0]; })); }).nThen(function (waitFor) { process.stdout.write(self + ' ' + highBits(self)); tracePath(target, self, cjdns, function (ret) { lastRet = ret; process.stdout.write(' ' + ret.ms + 'ms\n'); if (!ret.nodes || !ret.nodes.length) { console.log('cornered'); } else if (ret.nodes[0] !== ret.from) { process.stdout.write(ret.nodes[0] + ' ' + highBits(ret.nodes[0])); } }, waitFor()); }).nThen(function (waitFor) { if (!lastRet || lastRet.nodes[0] !== lastRet.from) { return; } console.log('success, trying reverse trace'); process.stdout.write(lastRet.from); tracePath(nodeToIP6(self), lastRet.from, cjdns, function (ret) { lastRet = ret; process.stdout.write(' ' + ret.ms + 'ms\n'); if (ret.result === 'timeout') { process.stdout.write('\n' + ret.from + ' ' + ret.result + '!'); } else if (!ret.nodes || !ret.nodes.length) { console.log('cornered'); } else if (ret.nodes[0] !== ret.from) { process.stdout.write(ret.nodes[0] + ' ' + highBits(ret.nodes[0])); } }, waitFor()); }).nThen(function (waitFor) { console.log(); cjdns.disconnect(); }); }; main(process.argv[process.argv.length-1]);