Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add extra anti-DoS tech to net.Server

  • Loading branch information...
commit 38dde9684f43dff636d1b798e7537b93d2b6b7fd 1 parent aeb9bed
@ry ry authored
Showing with 43 additions and 35 deletions.
  1. +1 −16 benchmark/idle_clients.js
  2. +42 −19 lib/net.js
View
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 () {
View
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;
Please sign in to comment.
Something went wrong with that request. Please try again.