Workaround for #724

This commit is contained in:
Calvin Montgomery 2017-12-06 22:09:13 -08:00
parent 60f77d4eb9
commit 9886f648f2
3 changed files with 63 additions and 8 deletions

View file

@ -2,7 +2,7 @@
"author": "Calvin Montgomery",
"name": "CyTube",
"description": "Online media synchronizer and chat",
"version": "3.51.5",
"version": "3.51.6",
"repository": {
"url": "http://github.com/calzoneman/sync"
},

View file

@ -21,7 +21,19 @@ import http from 'http';
const LOGGER = require('@calzoneman/jsli')('ioserver');
// WIP, not in use yet
const rateLimitExceeded = new Counter({
name: 'cytube_socketio_rate_limited_total',
help: 'Number of socket.io connections rejected due to exceeding rate limit'
});
const connLimitExceeded = new Counter({
name: 'cytube_socketio_conn_limited_total',
help: 'Number of socket.io connections rejected due to exceeding conn limit'
});
const authFailureCount = new Counter({
name: 'cytube_socketio_auth_error_total',
help: 'Number of failed authentications from session middleware'
});
class IOServer {
constructor(options = {
proxyTrustFn: proxyaddr.compile('127.0.0.1')
@ -65,6 +77,7 @@ class IOServer {
const bucket = this.ipThrottle.get(socket.context.ipAddress);
if (bucket.throttle()) {
rateLimitExceeded.inc(1);
LOGGER.info('Rejecting %s - exceeded connection rate limit',
socket.context.ipAddress);
next(new Error('Rate limit exceeded'));
@ -74,6 +87,8 @@ class IOServer {
next();
}
/*
TODO: see https://github.com/calzoneman/sync/issues/724
ipConnectionLimitMiddleware(socket, next) {
const ip = socket.context.ipAddress;
const count = this.ipCount.get(ip) || 0;
@ -84,12 +99,45 @@ class IOServer {
}
this.ipCount.set(ip, count + 1);
console.log(ip, this.ipCount.get(ip));
socket.once('disconnect', () => {
console.log('Disconnect event has fired for', socket.id);
this.ipCount.set(ip, this.ipCount.get(ip) - 1);
});
next();
}
*/
checkIPLimit(socket) {
const ip = socket.context.ipAddress;
const count = this.ipCount.get(ip) || 0;
if (count >= Config.get('io.ip-connection-limit')) {
connLimitExceeded.inc(1);
LOGGER.info(
'Rejecting %s - exceeded connection count limit',
ip
);
socket.emit('kick', {
reason: 'Too many connections from your IP address'
});
socket.disconnect(true);
return false;
}
this.ipCount.set(ip, count + 1);
socket.once('disconnect', () => {
const newCount = (this.ipCount.get(ip) || 1) - 1;
if (newCount === 0) {
this.ipCount.delete(ip);
} else {
this.ipCount.set(ip, newCount);
}
});
return true;
}
// Parse cookies
cookieParsingMiddleware(socket, next) {
@ -132,6 +180,7 @@ class IOServer {
promises.push(verifySession(auth).then(user => {
socket.context.user = Object.assign({}, user);
}).catch(error => {
authFailureCount.inc(1);
LOGGER.warn('Unable to verify session for %s - ignoring auth',
socket.context.ipAddress);
}));
@ -153,6 +202,12 @@ class IOServer {
}
handleConnection(socket) {
// TODO: move out of handleConnection if possible
// see: https://github.com/calzoneman/sync/issues/724
if (!this.checkIPLimit(socket)) {
return;
}
LOGGER.info('Accepted socket from %s', socket.context.ipAddress);
counters.add('socket.io:accept', 1);
socket.once('disconnect', () => counters.add('socket.io:disconnect', 1));
@ -176,7 +231,7 @@ class IOServer {
io.use(this.ipProxyMiddleware.bind(this));
io.use(this.ipBanMiddleware.bind(this));
io.use(this.ipThrottleMiddleware.bind(this));
io.use(this.ipConnectionLimitMiddleware.bind(this));
//io.use(this.ipConnectionLimitMiddleware.bind(this));
io.use(this.cookieParsingMiddleware.bind(this));
io.use(this.ipSessionCookieMiddleware.bind(this));
io.use(this.authUserMiddleware.bind(this));
@ -209,12 +264,12 @@ function patchSocketMetrics() {
Socket.prototype.onevent = function patchedOnevent() {
onevent.apply(this, arguments);
incomingEventCount.inc(1, new Date());
incomingEventCount.inc(1);
};
Socket.prototype.packet = function patchedPacket() {
packet.apply(this, arguments);
outgoingPacketCount.inc(1, new Date());
outgoingPacketCount.inc(1);
};
}
@ -278,7 +333,7 @@ function emitMetrics(sock) {
let closed = false;
let transportName = sock.client.conn.transport.name;
promSocketCount.inc({ transport: transportName });
promSocketAccept.inc(1, new Date());
promSocketAccept.inc(1);
sock.client.conn.on('upgrade', newTransport => {
try {
@ -298,7 +353,7 @@ function emitMetrics(sock) {
try {
closed = true;
promSocketCount.dec({ transport: transportName });
promSocketDisconnect.inc(1, new Date());
promSocketDisconnect.inc(1);
} catch (error) {
LOGGER.error('Error emitting disconnect metrics for socket (ip=%s): %s',
sock.context.ipAddress, error.stack);

View file

@ -37,7 +37,7 @@ Callbacks = {
// Socket.IO error callback
error: function (msg) {
window.SOCKET_ERROR_REASON = reason;
window.SOCKET_ERROR_REASON = msg;
$("<div/>")
.addClass("server-msg-disconnect")
.text("Unable to connect: " + msg)