diff --git a/config.js b/config.js index 23959838..cc79475a 100644 --- a/config.js +++ b/config.js @@ -195,5 +195,34 @@ module.exports = { // @default "" // certificate: "" + }, + + // + // Allows shout to run as an identd + // + // @type object + // @default {} + identd: { + // + // Enable Identd daemon + // + // @type boolean + // @default true + enable: true, + + // + // Port to listen for ident requests + // + // @type int + // @default 30113 + port: 30113, + + // + // Default user to return on unknown request + // if false, will return NOUSER + // + // @type string + // @default shout + default: "shout" } }; diff --git a/src/client.js b/src/client.js index fb6b9c0d..cd47f275 100644 --- a/src/client.js +++ b/src/client.js @@ -8,6 +8,7 @@ var Network = require("./models/network"); var slate = require("slate-irc"); var tls = require("tls"); var Helper = require("./helper"); +var identd = require("./identd"); module.exports = Client; @@ -135,6 +136,25 @@ Client.prototype.connect = function(args) { } var stream = args.tls ? tls.connect(server) : net.connect(server); + var identdItem = null; + var cb = function() { + identdItem = { + "remoteIp": stream.remoteAddress, + "remotePort": stream.remotePort, + "localPort": stream.localPort, + "username": username + }; + + identd.addConnection(identdItem); + }; + + var stream; + if (args.tls) { + stream = tls.connect(server); + stream.socket.on('connect', cb); + } else { + stream = net.connect(server, cb); + } stream.on("error", function(e) { console.log("Client#connect():\n" + e); @@ -148,6 +168,10 @@ Client.prototype.connect = function(args) { }); }); + stream.on("close", function() { + identd.removeConnection(identdItem); + }); + var nick = args.nick || "shout-user"; var username = args.username || nick; var realname = args.realname || "Shout User"; diff --git a/src/identd.js b/src/identd.js new file mode 100644 index 00000000..5b35e868 --- /dev/null +++ b/src/identd.js @@ -0,0 +1,90 @@ +var _ = require("lodash"); +var net = require("net"); +var Helper = require("./helper"); + +function Identd() { + // used to store who is connecting... + this.connections = []; + this.server = null; + this.config = { + enable: false, + port: 30113, + default: "shout" + }; +}; + +Identd.prototype.respond = function(remoteIp, localPort, remotePort) { + // Build the first part (always the same) + var response = localPort + ", " + remotePort + " : "; + var params = {"remoteIp": remoteIp, "remotePort": remotePort, "localPort": localPort}; + var connection = _.where(this.connections, params); + if (connection.length == 0) { + params["localPort"] = undefined; + connection = _.where(this.connections, params); + } + + if (connection.length > 0) { + // We have some connections, but we only want the first + connection = _.first(connection); + response += " USERID : UNIX : " + connection.username; + // We're done with that connection. Remove it + this.removeConnection(connection); + } else { + if (this.config.default == null) { + response += " ERROR : NOUSER"; + } else { + var ident = this.config.default.replace(/\?/g, function(a) { + return Math.floor(Math.random() * 10); + }); + response += " USERID : UNIX : " + ident; + } + } + // responses must end with CR+LF + return response + "\r\n"; +}; + +Identd.prototype.parse = function(request) { + // myPort, theirPort\r\n + request = request.toString().split(/,\s*/); + if (request.length == 2) { + var localPort = parseInt(request[0]), + remotePort = parseInt(request[1]); + } + return [localPort, remotePort]; +}; + +Identd.prototype.start = function(config) { + _.merge(this.config, config.identd); + + if (this.config.enable) { + var self = this; + + // create the server + this.server = net.createServer(function(socket) { + socket.on('data', function(data) { + var parsed = self.parse(data); + // parse and generate a response + var response = self.respond(socket.remoteAddress, parsed[0], parsed[1]); + socket.write(response); + socket.end(); + }); + }); + this.server.listen(this.config.port); + } + + return self; +}; + +Identd.prototype.addConnection = function(connection) { + if (this.config.enable) { + this.connections.push(connection); + } +}; + +Identd.prototype.removeConnection = function(connection) { + if (this.config.enable) { + this.connections = _.without(this.connections, connection); + } +}; + +module.exports = new Identd(); diff --git a/src/server.js b/src/server.js index 374b0025..c9755ebf 100644 --- a/src/server.js +++ b/src/server.js @@ -36,6 +36,10 @@ module.exports = function(options) { }, app).listen(port, host) } + if (config.identd && config.identd.enable) { + require("./identd").start(config); + } + sockets = io(server); sockets.on("connect", function(socket) { if (config.public) {