Add extra anti-DoS tech to net.Server
This commit is contained in:
parent
aeb9bed63e
commit
38dde9684f
@ -4,21 +4,6 @@ var errors = 0, connections = 0;
|
||||
|
||||
var lastClose = 0;
|
||||
|
||||
function maybeConnect (s) {
|
||||
var now = new Date();
|
||||
if (now - lastClose > 5000) {
|
||||
// Just connect immediately
|
||||
connect();
|
||||
} else {
|
||||
// Otherwise wait a little - see if this one is connected still. Just to
|
||||
// avoid spinning at 100% cpu when the server totally rejects our
|
||||
// connections.
|
||||
setTimeout(function () {
|
||||
if (s.writable && s.readable) connect();
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
function connect () {
|
||||
process.nextTick(function () {
|
||||
var s = net.Stream();
|
||||
@ -28,7 +13,7 @@ function connect () {
|
||||
s.on('connect', function () {
|
||||
gotConnected = true;
|
||||
connections++;
|
||||
maybeConnect(s);
|
||||
connect();
|
||||
});
|
||||
|
||||
s.on('close', function () {
|
||||
|
67
lib/net.js
67
lib/net.js
@ -911,7 +911,7 @@ function Server (/* [ options, ] listener */) {
|
||||
if (typeof arguments[0] == "object") {
|
||||
options = arguments[0];
|
||||
}
|
||||
|
||||
|
||||
// listener: find the last argument that is a function
|
||||
for (var l = arguments.length - 1; l >= 0; l--) {
|
||||
if (typeof arguments[l] == "function") {
|
||||
@ -930,33 +930,56 @@ function Server (/* [ options, ] listener */) {
|
||||
// Just in case we don't have a dummy fd.
|
||||
if (!self._dummyFD) self._getDummyFD();
|
||||
|
||||
if (self._acceptTimer) {
|
||||
// Somehow the watcher got started again. Need to wait until
|
||||
// the timer finishes.
|
||||
self.watcher.stop();
|
||||
}
|
||||
|
||||
while (self.fd) {
|
||||
try {
|
||||
var peerInfo = accept(self.fd);
|
||||
} catch (e) {
|
||||
if (e.errno == EMFILE) {
|
||||
// Output a warning, but only at most every 5 seconds.
|
||||
var now = new Date();
|
||||
if (now - self._lastEMFILEWarning > 5000) {
|
||||
console.error("(node) Hit max file limit. Increase 'ulimit -n'.");
|
||||
}
|
||||
self._lastEMFILEWarning = now;
|
||||
if (e.errno != EMFILE) throw e;
|
||||
|
||||
// Gracefully reject pending clients by freeing up a file
|
||||
// descriptor.
|
||||
if (self._dummyFD) {
|
||||
close(self._dummyFD);
|
||||
self._dummyFD = null;
|
||||
while (true) {
|
||||
peerInfo = accept(self.fd);
|
||||
if (!peerInfo) break;
|
||||
close(peerInfo.fd);
|
||||
}
|
||||
self._getDummyFD();
|
||||
}
|
||||
return;
|
||||
// Output a warning, but only at most every 5 seconds.
|
||||
var now = new Date();
|
||||
if (now - self._lastEMFILEWarning > 5000) {
|
||||
console.error("(node) Hit max file limit. Increase 'ulimit -n'.");
|
||||
self._lastEMFILEWarning = now;
|
||||
}
|
||||
throw e;
|
||||
|
||||
var acceptCount = 0;
|
||||
|
||||
// Gracefully reject pending clients by freeing up a file
|
||||
// descriptor.
|
||||
if (self._dummyFD) {
|
||||
close(self._dummyFD); // Free up an fd
|
||||
self._dummyFD = null;
|
||||
// Accept and close the waiting clients one at a time.
|
||||
// Single threaded programming ftw.
|
||||
while (true) {
|
||||
peerInfo = accept(self.fd);
|
||||
if (!peerInfo) break;
|
||||
close(peerInfo.fd);
|
||||
|
||||
// Don't become DoS'd by incoming requests
|
||||
if (++acceptCount > 50) {
|
||||
assert(!self._acceptTimer);
|
||||
self.watcher.stop();
|
||||
// Wait a second before accepting more.
|
||||
self._acceptTimer = setTimeout(function () {
|
||||
assert(parseInt(self.fd) >= 0);
|
||||
self._acceptTimer = null;
|
||||
self.watcher.start();
|
||||
}, 1000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Reacquire the dummy fd
|
||||
self._getDummyFD();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!peerInfo) return;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user