diff --git a/defaults/config.js b/defaults/config.js index f84196e9..22312601 100644 --- a/defaults/config.js +++ b/defaults/config.js @@ -109,6 +109,17 @@ module.exports = { // lockNetwork: false, + // + // Hex IP + // + // If enabled, clients' username will be set to their IP encoded has hex. + // This is done to share the real user IP address with the server for host masking purposes. + // + // @type boolean + // @default false + // + useHexIp: false, + // // WEBIRC support // diff --git a/src/client.js b/src/client.js index dea63512..88efe83c 100644 --- a/src/client.js +++ b/src/client.js @@ -175,6 +175,9 @@ Client.prototype.connect = function(args) { }); } + args.ip = args.ip || (client.config && client.config.ip) || client.ip; + args.hostname = args.hostname || (client.config && client.config.hostname) || client.hostname; + var network = new Network({ name: args.name || "", host: args.host || "", @@ -219,8 +222,9 @@ Client.prototype.connect = function(args) { } if (config.webirc && network.host in config.webirc) { - args.ip = args.ip || (client.config && client.config.ip) || client.ip; - args.hostname = args.hostname || (client.config && client.config.hostname) || client.hostname || args.ip; + if (!args.hostname) { + args.hostname = args.ip; + } if (args.ip) { if (config.webirc[network.host] instanceof Function) { @@ -259,7 +263,7 @@ Client.prototype.connect = function(args) { host: network.host, port: network.port, nick: nick, - username: network.username, + username: config.useHexIp ? Helper.ip2hex(args.ip) : network.username, gecos: network.realname, password: network.password, tls: network.tls, @@ -270,6 +274,8 @@ Client.prototype.connect = function(args) { auto_reconnect_max_retries: 360, // At least one hour (plus timeouts) worth of reconnections webirc: webirc, }); + + client.save(); }; Client.prototype.updateToken = function(callback) { @@ -456,7 +462,31 @@ Client.prototype.quit = function() { }; Client.prototype.clientAttach = function(socketId) { - this.attachedClients[socketId] = this.lastActiveChannel; + var client = this; + var save = false; + + client.attachedClients[socketId] = client.lastActiveChannel; + + // Update old networks to store ip and hostmask + client.networks.forEach(network => { + if (!network.ip) { + save = true; + network.ip = (client.config && client.config.ip) || client.ip; + } + + if (!network.hostname) { + var hostmask = (client.config && client.config.hostname) || client.hostname; + + if (hostmask) { + save = true; + network.hostmask = hostmask; + } + } + }); + + if (save) { + client.save(); + } }; Client.prototype.clientDetach = function(socketId) { diff --git a/src/helper.js b/src/helper.js index d4af765f..68e88919 100644 --- a/src/helper.js +++ b/src/helper.js @@ -5,6 +5,7 @@ var _ = require("lodash"); var path = require("path"); var os = require("os"); var fs = require("fs"); +var net = require("net"); var bcrypt = require("bcrypt-nodejs"); var Helper = { @@ -15,6 +16,7 @@ var Helper = { setHome: setHome, getVersion: getVersion, getGitCommit: getGitCommit, + ip2hex: ip2hex, password: { hash: passwordHash, @@ -75,6 +77,23 @@ function getUserLogsPath(name, network) { return path.join(this.HOME, "logs", name, network); } +function ip2hex(address) { + // no ipv6 support + if (!net.isIPv4(address)) { + return "00000000"; + } + + return address.split(".").map(function(octet) { + var hex = parseInt(octet, 10).toString(16); + + if (hex.length === 1) { + hex = "0" + hex; + } + + return hex; + }).join(""); +} + function expandHome(shortenedPath) { var home; diff --git a/src/server.js b/src/server.js index 1e03e918..62cea3a4 100644 --- a/src/server.js +++ b/src/server.js @@ -147,6 +147,8 @@ function init(socket, client) { } else { socket.emit("authorized"); + client.ip = getClientIp(socket.request); + socket.on("disconnect", function() { client.clientDetach(socket.id); }); diff --git a/test/tests/hexip.js b/test/tests/hexip.js new file mode 100644 index 00000000..255903c3 --- /dev/null +++ b/test/tests/hexip.js @@ -0,0 +1,19 @@ +"use strict"; + +const expect = require("chai").expect; +const Helper = require("../../src/helper"); + +describe("HexIP", function() { + it("should correctly convert IPv4 to hex", function() { + expect(Helper.ip2hex("66.124.160.150")).to.equal("427ca096"); + expect(Helper.ip2hex("127.0.0.1")).to.equal("7f000001"); + expect(Helper.ip2hex("0.0.0.255")).to.equal("000000ff"); + }); + + it("unsupported addresses return default", function() { + expect(Helper.ip2hex("0.0.0.999")).to.equal("00000000"); + expect(Helper.ip2hex("localhost")).to.equal("00000000"); + expect(Helper.ip2hex("::1")).to.equal("00000000"); + expect(Helper.ip2hex("2606:2800:220:1:248:1893:25c8:1946")).to.equal("00000000"); + }); +});