X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;ds=sidebyside;f=server%2Fweblistener.js;h=964118b6786fb671562abb210a0d4c2d886bbc5b;hb=df0aee0935acf9a94f15a3f118cd0d439ba70ef5;hp=80fb2af7e7350a7d4a1f6aa8e25a48641aee7055;hpb=c12b3e40bed908ee20f58e7a7731666f33394ce5;p=KiwiIRC.git diff --git a/server/weblistener.js b/server/weblistener.js index 80fb2af..964118b 100644 --- a/server/weblistener.js +++ b/server/weblistener.js @@ -1,16 +1,18 @@ -var ws = require('socket.io'), - events = require('events'), - http = require('http'), - https = require('https'), - util = require('util'), - fs = require('fs'), - dns = require('dns'), - url = require('url'), - _ = require('lodash'), - Client = require('./client.js').Client, - HttpHandler = require('./httphandler.js').HttpHandler, - rehash = require('./rehash.js'), - range_check = require('range_check'); +var engine = require('engine.io'), + WebsocketRpc = require('./websocketrpc.js'); + events = require('events'), + http = require('http'), + https = require('https'), + util = require('util'), + fs = require('fs'), + dns = require('dns'), + url = require('url'), + _ = require('lodash'), + spdy = require('spdy'), + ipaddr = require('ipaddr.js'), + Client = require('./client.js').Client, + HttpHandler = require('./httphandler.js').HttpHandler, + rehash = require('./rehash.js'); @@ -24,21 +26,14 @@ rehash.on('rehashed', function (files) { var http_handler; -var WebListener = function (web_config, transports) { - var hs, opts, ws_opts, +var WebListener = module.exports = function (web_config) { + var hs, opts, that = this; events.EventEmitter.call(this); - - http_handler = new HttpHandler(web_config); - - // Standard options for the socket.io connections - ws_opts = { - 'log level': 0, - 'log colors': 0 - }; + http_handler = new HttpHandler(web_config); if (web_config.ssl) { opts = { @@ -57,10 +52,8 @@ var WebListener = function (web_config, transports) { } } - hs = https.createServer(opts, handleHttpRequest); - - // Start socket.io listening on this weblistener - this.ws = ws.listen(hs, _.extend({ssl: true}, ws_opts)); + hs = spdy.createServer(opts, handleHttpRequest); + hs.listen(web_config.port, web_config.address, function () { that.emit('listening'); }); @@ -69,8 +62,6 @@ var WebListener = function (web_config, transports) { // Start some plain-text server up hs = http.createServer(handleHttpRequest); - // Start socket.io listening on this weblistener - this.ws = ws.listen(hs, _.extend({ssl: false}, ws_opts)); hs.listen(web_config.port, web_config.address, function () { that.emit('listening'); }); @@ -78,31 +69,51 @@ var WebListener = function (web_config, transports) { hs.on('error', function (err) { that.emit('error', err); - }) - - this.ws.enable('browser client minification'); - this.ws.enable('browser client etag'); - this.ws.set('transports', transports); - this.ws.set('resource', (global.config.http_base_path || '') + '/transport'); - - this.ws.of('/kiwi').authorization(authoriseConnection) - .on('connection', function () { - newConnection.apply(that, arguments); - } - ); - this.ws.of('/kiwi').on('error', console.log); + }); + + this.ws = engine.attach(hs, { + path: (global.config.http_base_path || '') + '/transport' + }); + + this.ws.on('connection', function(socket) { + initialiseSocket(socket, function(err, authorised) { + var client; + + if (!authorised) { + socket.close(); + return; + } + + client = new Client(socket); + client.on('dispose', function () { + that.emit('client_dispose', this); + }); + + that.emit('connection', client); + + // Call any modules listening for new clients + global.modules.emit('client created', {client: client}); + }); + }); }; util.inherits(WebListener, events.EventEmitter); function handleHttpRequest(request, response) { - var uri = url.parse(request.url, true); - - // If this isn't a socket.io request, pass it onto the http handler - if (uri.pathname.substr(0, 10) !== '/socket.io') { - http_handler.serve(request, response); + http_handler.serve(request, response); +} + +function rangeCheck(addr, range) { + var i, ranges, parts; + ranges = (!_.isArray(range)) ? [range] : range; + for (i = 0; i < ranges.length; i++) { + parts = ranges[i].split('/'); + if (ipaddr.process(addr).match(ipaddr.process(parts[0]), parts[1])) { + return true; + } } + return false; } @@ -110,54 +121,68 @@ function handleHttpRequest(request, response) { * Get the reverse DNS entry for this connection. * Used later on for webirc, etc functionality */ -function authoriseConnection(handshakeData, callback) { - var address = handshakeData.address.address; +function initialiseSocket(socket, callback) { + var request = socket.request, + address = request.connection.remoteAddress, + revdns; + + // Key/val data stored to the socket to be read later on + // May also be synced to a redis DB to lookup clients + socket.meta = {}; // If a forwarded-for header is found, switch the source address - if (handshakeData.headers[global.config.http_proxy_ip_header || 'x-forwarded-for']) { + if (request.headers[global.config.http_proxy_ip_header || 'x-forwarded-for']) { // Check we're connecting from a whitelisted proxy - if (!global.config.http_proxies || !range_check.in_range(address, global.config.http_proxies)) { + if (!global.config.http_proxies || !rangeCheck(address, global.config.http_proxies)) { console.log('Unlisted proxy:', address); callback(null, false); return; } // We're sent from a whitelisted proxy, replace the hosts - address = handshakeData.headers['x-forwarded-for']; + address = request.headers[global.config.http_proxy_ip_header || 'x-forwarded-for']; } - handshakeData.real_address = address; - + socket.meta.real_address = address; + // If enabled, don't go over the connection limit if (global.config.max_client_conns && global.config.max_client_conns > 0) { if (global.clients.numOnAddress(address) + 1 > global.config.max_client_conns) { return callback(null, false); } } - - dns.reverse(address, function (err, domains) { - if (err || domains.length === 0) { - handshakeData.revdns = address; - } else { - handshakeData.revdns = _.first(domains) || address; - } - - // All is well, authorise the connection - callback(null, true); - }); -} - -function newConnection(websocket) { - var client, that = this; - client = new Client(websocket); - client.on('dispose', function () { - that.emit('client_dispose', this); - }); - this.emit('connection', client); -} + try { + dns.reverse(address, function (err, domains) { + if (!err && domains.length > 0) { + revdns = _.first(domains); + } + if (!revdns) { + // No reverse DNS found, use the IP + socket.meta.revdns = address; + callback(null, true); + } else { + // Make sure the reverse DNS matches the A record to use the hostname.. + dns.lookup(revdns, function (err, ip_address, family) { + if (!err && ip_address == address) { + // A record matches PTR, perfectly valid hostname + socket.meta.revdns = revdns; + } else { + // A record does not match the PTR, invalid hostname + socket.meta.revdns = address; + } + + // We have all the info we need, proceed with the connection + callback(null, true); + }); + } + }); -module.exports = WebListener; + } catch (err) { + socket.meta.revdns = address; + callback(null, true); + } +}