Browse Source

Add extra anti-DoS tech to net.Server

v0.7.4-release
Ryan Dahl 15 years ago
parent
commit
38dde9684f
  1. 17
      benchmark/idle_clients.js
  2. 61
      lib/net.js

17
benchmark/idle_clients.js

@ -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 () {

61
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'.");
}
if (e.errno != EMFILE) throw e;
// 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;
}
// 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);
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;
}
self._getDummyFD();
}
return;
// Reacquire the dummy fd
self._getDummyFD();
}
throw e;
return;
}
if (!peerInfo) return;

Loading…
Cancel
Save