Permalink
Browse files

prelimiary support for 'fingerprint' fields in Namecoin records

  • Loading branch information...
itsnotlupus committed Jul 24, 2011
1 parent fd10e3b commit 5aa9da17b0bd777461bf67ddcc47e332218560dc
Showing with 186 additions and 81 deletions.
  1. +17 −0 README.md
  2. +4 −1 lib/name_scan.js
  3. +3 −2 lib/nmcdns.js
  4. +23 −13 lib/nmcresolver.js
  5. +72 −23 lib/nmcsocks.js
  6. +62 −38 lib/nmctls.js
  7. +4 −3 lib/tester.js
  8. +1 −1 package.json
View
@@ -77,6 +77,22 @@ If you are using the source version, you will also need:
- node ( http://nodejs.org/ )
- optimist and binary ( `npm install optimist binary `)
+If you are building from the top of the tree, you will also need:
+
+- dcrypt . `npm install dcrypt` would normally work, but I rely on
+ a couple of patches that aren't in it yet, so you'll need to grab it from
+ https://github.com/itsnotlupus/dcrypt . Put that under nmcsocks/node_modules/dcrypt,
+ and build it with `node-waf configure build`. That ought to do it.
+
+## new stuff to pay attention to:
+
+If you're trying to use the new "fingerprint" support code, you'll need to add the
+X.509 CA certificate NmcSocks creates locally into your browser. The procedure varies
+for each browser. The CA certificate is located under <NmcSocksDataDir>/namecoin_root.crt
+On unix, <NmcSocksDataDir> is ~/.nmcsocks/
+On windows, it's %APP_DATA%/NmcSocks/
+Mac Users, look under ~/Library/Application\ Support/NmcSocks/
+
## todo
- ipv6 support
@@ -88,3 +104,4 @@ If you are using the source version, you will also need:
v0.2: better draft spec support (delegate/import/alias stuff), infinite loop mitigation
v0.3: embedded DNS server to resolve .bit domains
v0.4: better DNS server support, various bug fixes
+ v0.5: support for the "fingerprint" record field, enabled decentralized TLS certificate trust.
View
@@ -75,6 +75,9 @@ module.exports = {
"ftp": { "delegate": [ "d/domain", "eu" ] },
"us": { "ip": "192.168.0.0" }
}
+ },
+ "d/tlstest": {
+ "ip": "192.168.1.90",
+ "fingerprint": [ "07:3B:39:56:0A:A8:80:76:8A:B1:34:9C:B6:36:F7:56:5B:4C:13:E0" ]
}
-
};
View
@@ -38,8 +38,9 @@ function startServer(port, host, callback) {
if (err) {
return console.log("Resolver error:", err);
}
- for (var i=0,l=data.length;i<l;i++) {
- var type, answer=data[i];
+ var answers = data.answer;
+ for (var i=0,l=answers.length;i<l;i++) {
+ var type, answer=answers[i];
switch (net.isIP(answer)) {
case 0: type = ndns.ns_t.cname; break;
case 4: type = ndns.ns_t.a; break;
View
@@ -66,28 +66,32 @@ function resolveHostWithNamecoin(host, type, counter, callback) {
case types.HOST:
case types.TOR:
case types.I2P:
- callback(null, host);
+ callback(null, resolverAnswer(host));
break;
case types.IPV4:
if (net.isIP(host)==4) {
- callback(null, host);
+ callback(null, resolverAnswer(host));
} else {
// take our chances with a resolver, if we can.
if (private_mode) {
callback(new Error("Cannot resolve this host in private mode."));
} else {
- dns.resolve4(host, callback);
+ dns.resolve4(host, function(err, data){
+ callback(err, resolverAnswer(data));
+ });
}
}
break;
case types.IPV6:
if (net.isIP(host)==6) {
- callback(null, host);
+ callback(null, resolverAnswer(host));
} else {
if (private_mode) {
callback(new Error("Cannot resolve this host in private mode."));
} else {
- dns.resolve6(host, callback);
+ dns.resolve6(host, function(err, data){
+ callback(err, resolverAnswer(data));
+ });
}
}
break;
@@ -274,7 +278,7 @@ function resolveFromValue(host, type, parent, chunks, value, counter, callback)
if (err) {
postDNSprocessing();
} else {
- callback(null, data);
+ callback(null, resolverAnswer(data, value.fingerprint));
}
});
} else {
@@ -305,16 +309,16 @@ function resolveFromValue(host, type, parent, chunks, value, counter, callback)
// 1. legacy crap: if value a string?
if (typeof value == "string") {
- return callback(null, value);
+ return callback(null, resolverAnswer(value)); // no fingerprints evar in this case
}
// enforce tor_mode
if ((tor_mode || type==types.TOR) && value.tor) {
- return callback(null, value.tor);
+ return callback(null, resolverAnswer(value.tor, value.fingerprint)); // can .onion sites use https?
}
// enforce i2p_mode
if ((i2p_mode || type==types.I2P) && value.i2p) {
- return callback(null, value.i2p.b32);
+ return callback(null, resolverAnswer(value.i2p.b32, value.fingerprint)); // I2P over SSL?
}
// 2. else, find some other hardcoded value to use.
@@ -323,14 +327,14 @@ function resolveFromValue(host, type, parent, chunks, value, counter, callback)
ip = value.ip;
// if it's not an ipv4 address, we ignore it.
if (net.isIP(oneOf(ip))==4) {
- return callback(null, ip);
+ return callback(null, resolverAnswer(ip, value.fingerprint));
}
}
if (value.ip6 && (type==types.ANY || type==types.IPV6)) {
ip = value.ip6;
// if it's not an ipv6 address, we ignore it.
if (net.isIP(oneOf(ip))==6) {
- return callback(null, ip);
+ return callback(null, resolverAnswer(ip, value.fingerprint));
}
}
@@ -371,6 +375,12 @@ function resolveWithDNS(host, server, callback) {
});
}
+function resolverAnswer(answer, fingerprint) {
+ return {
+ answer: arrayOf(answer),
+ fingerprint: arrayOf(fingerprint)
+ };
+}
function testMode() {
testing = true;
@@ -397,15 +407,15 @@ module.exports = {
types: types,
resolve: function(host, callback) {
return resolveHostWithNamecoin(host, types.ANY, 0, function(err, value){
- callback(err, oneOf(value));
+ callback(err, value);
});
},
/**
*
*/
resolveFull: function(host, type, callback) {
return resolveHostWithNamecoin(host, type, 0, function(err,value) {
- callback(err, arrayOf(value));
+ callback(err, value);
});
},
setPrivateMode: function(flag) { private_mode = !!flag; },
View
@@ -5,6 +5,7 @@ var net = require("net");
var binary = require("binary");
var resolver = require("./nmcresolver");
var rpc = require("./nmcrpc");
+var nmctls = require("./nmctls");
var argv = require("optimist")
.usage("Start a NameCoin Socks 5 Proxy.\nUsage: $0")
@@ -56,9 +57,11 @@ var argv = require("optimist")
describe: "IP address for the DNS server to listen on"
})
.options("dir", {
- alias: "d",
describe: "Namecoin configuration directory"
})
+ .options("test", {
+ describe: "Test mode. Enable some static namecoin records. Not for general use."
+ })
.options("help", {
alias: "h",
describe: "Display this help message"
@@ -81,6 +84,13 @@ switch(true){
// namecoin config directory handling
if (argv.dir) {
+ try {
+ fs.statSync(argv.dir);
+ if (!fs.isDirectory) { throw "no"; }
+ } catch (e) {
+ console.log("Error: namecoin config --dir value is not a valid directory.");
+ process.exit(1);
+ }
rpc.setDataDir(argv.dir);
console.log("Using namecoin config directory: ", rpc.getDataDir());
}
@@ -105,6 +115,11 @@ if (argv.private) {
console.log("Private mode is enabled.");
}
+// test mode, mostly for dev stuff. don't use this, mm'kay?
+if (argv.test) {
+ resolver.testMode();
+}
+
function namecoinRpcTester(next) {
rpc.call("getinfo",[],function(err,data) {
if (err) {
@@ -256,10 +271,10 @@ function new_client(client) {
});
}
-function socks_do(t, client, host, port, response) {
+function socks_do(t, client, hostname, port, response) {
// resolve "host" through NameCoin, if applicable
- resolver.resolve(host, function(err, host) {
+ resolver.resolve(hostname, function(err, data) {
if (err) {
response[1] = 4;
@@ -268,9 +283,38 @@ function socks_do(t, client, host, port, response) {
return;
}
+ var host = data.answer[0]; // XXX for extra point, loop through the answer if the previous ones fail.
+
switch (t) {
case 1:
- socks_connect(client, host, port, response); break;
+ if (data.fingerprint && data.fingerprint.length && port == 443) { // hardcoded port.. this is not awesome, design-wise.
+ // take the SSL MITM path instead.
+ nmctls.clientConnect(port, host, hostname, data.fingerprint, function(err, socket) {
+
+ if(err) {
+ console.log("10: NmcSocks frowns upon your puny SSL server.",err);
+ return;
+ }
+ console.log("10: NmcSocks approves of your SSL connection.");
+ // needed to allow the other side of the TLS setup to work
+ client.on("data", function(data){
+ console.log("browser sent: ",data);
+ });
+ nmctls.serverConnect(client, hostname, function(client) {
+ console.log("30: It seems to have worked. piping the two ends now.");
+ client.setMaxListeners(30);
+ socket.setMaxListeners(30);
+
+ client.pipe(socket);
+ socket.pipe(client);
+ });
+ client.write(new Buffer(response));
+ console.log("20: ok, waiting for tls initiation to be done on the client side now.");
+ });
+ } else {
+ socks_connect(client, host, port, response);
+ }
+ break;
case 2:
socks_bind(client, host, port); break;
case 3:
@@ -331,7 +375,9 @@ function socks_connect(client, host, port, response) {
if (argv.chain == "never") {
socket = new net.Socket({type: 'tcp4'});
- socket.connect(port, host, socketHandler);
+ socket.connect(port, host, function() {
+ socketHandler(client, socket, response);
+ });
socket.once("error", socketErrorHandler);
} else {
openSocksSocket(argv.shost, argv.sport, host, port, function(err, data){
@@ -342,39 +388,42 @@ function socks_connect(client, host, port, response) {
} else {
socket = new net.Socket({type: 'tcp4'});
socket.once("error", socketErrorHandler);
- socket.connect(port, host, socketHandler);
+ socket.connect(port, host, function() {
+ socketHandler(client, socket, response);
+ });
}
} else {
socket = data;
socket.once("error", socketErrorHandler);
- socketHandler();
+ socketHandler(client, socket, response);
}
});
}
- function socketHandler() {
-
- client.setMaxListeners(30);
- socket.setMaxListeners(30);
-
- client.pipe(socket);
- socket.pipe(client);
-
- // everything is setup. let the client know about it.
- try {
- client.write(new Buffer(response));
- } catch (e) {
- // the client hang up on me? lame.
- }
-
- };
function socketErrorHandler(e) {
response[1]=4; // XXX may not be the right error..
client.end(new Buffer(response));
console.log("Error: ",e.message," while connecting to ",host,":",port);
}
}
+function socketHandler(client, socket, response) {
+
+ client.setMaxListeners(30);
+ socket.setMaxListeners(30);
+
+ client.pipe(socket);
+ socket.pipe(client);
+
+ // everything is setup. let the client know about it.
+ try {
+ client.write(new Buffer(response));
+ } catch (e) {
+ // the client hang up on me? lame.
+ }
+
+};
+
function socks_bind(client, host, port) {
throw new Error("socks_bind not implemented.");
}
Oops, something went wrong.

0 comments on commit 5aa9da1

Please sign in to comment.