| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // The tests in this file attempt to verify the following through simulation: | 5 // The tests in this file attempt to verify the following through simulation: |
| 6 // a) That a server experiencing overload will actually benefit from the | 6 // a) That a server experiencing overload will actually benefit from the |
| 7 // anti-DDoS throttling logic, i.e. that its traffic spike will subside | 7 // anti-DDoS throttling logic, i.e. that its traffic spike will subside |
| 8 // and be distributed over a longer period of time; | 8 // and be distributed over a longer period of time; |
| 9 // b) That "well-behaved" clients of a server under DDoS attack actually | 9 // b) That "well-behaved" clients of a server under DDoS attack actually |
| 10 // benefit from the anti-DDoS throttling logic; and | 10 // benefit from the anti-DDoS throttling logic; and |
| 11 // c) That the approximate increase in "perceived downtime" introduced by | 11 // c) That the approximate increase in "perceived downtime" introduced by |
| 12 // anti-DDoS throttling for various different actual downtimes is what | 12 // anti-DDoS throttling for various different actual downtimes is what |
| 13 // we expect it to be. | 13 // we expect it to be. |
| 14 | 14 |
| 15 #include <stddef.h> | 15 #include <stddef.h> |
| 16 | 16 |
| 17 #include <cmath> | 17 #include <cmath> |
| 18 #include <limits> | 18 #include <limits> |
| 19 #include <memory> |
| 19 #include <vector> | 20 #include <vector> |
| 20 | 21 |
| 21 #include "base/environment.h" | 22 #include "base/environment.h" |
| 22 #include "base/macros.h" | 23 #include "base/macros.h" |
| 23 #include "base/memory/scoped_ptr.h" | 24 #include "base/memory/ptr_util.h" |
| 24 #include "base/message_loop/message_loop.h" | 25 #include "base/message_loop/message_loop.h" |
| 25 #include "base/rand_util.h" | 26 #include "base/rand_util.h" |
| 26 #include "base/time/time.h" | 27 #include "base/time/time.h" |
| 27 #include "extensions/browser/extension_throttle_manager.h" | 28 #include "extensions/browser/extension_throttle_manager.h" |
| 28 #include "extensions/browser/extension_throttle_test_support.h" | 29 #include "extensions/browser/extension_throttle_test_support.h" |
| 29 #include "net/base/request_priority.h" | 30 #include "net/base/request_priority.h" |
| 30 #include "net/url_request/url_request.h" | 31 #include "net/url_request/url_request.h" |
| 31 #include "net/url_request/url_request_context.h" | 32 #include "net/url_request/url_request_context.h" |
| 32 #include "net/url_request/url_request_test_util.h" | 33 #include "net/url_request/url_request_test_util.h" |
| 33 #include "testing/gtest/include/gtest/gtest.h" | 34 #include "testing/gtest/include/gtest/gtest.h" |
| (...skipping 13 matching lines...) Expand all Loading... |
| 47 const char kShowSimulationVariableName[] = "SHOW_SIMULATION_RESULTS"; | 48 const char kShowSimulationVariableName[] = "SHOW_SIMULATION_RESULTS"; |
| 48 | 49 |
| 49 // Prints output only if a given environment variable is set. We use this | 50 // Prints output only if a given environment variable is set. We use this |
| 50 // to not print any output for human evaluation when the test is run without | 51 // to not print any output for human evaluation when the test is run without |
| 51 // supervision. | 52 // supervision. |
| 52 void VerboseOut(const char* format, ...) { | 53 void VerboseOut(const char* format, ...) { |
| 53 static bool have_checked_environment = false; | 54 static bool have_checked_environment = false; |
| 54 static bool should_print = false; | 55 static bool should_print = false; |
| 55 if (!have_checked_environment) { | 56 if (!have_checked_environment) { |
| 56 have_checked_environment = true; | 57 have_checked_environment = true; |
| 57 scoped_ptr<base::Environment> env(base::Environment::Create()); | 58 std::unique_ptr<base::Environment> env(base::Environment::Create()); |
| 58 if (env->HasVar(kShowSimulationVariableName)) | 59 if (env->HasVar(kShowSimulationVariableName)) |
| 59 should_print = true; | 60 should_print = true; |
| 60 } | 61 } |
| 61 | 62 |
| 62 if (should_print) { | 63 if (should_print) { |
| 63 va_list arglist; | 64 va_list arglist; |
| 64 va_start(arglist, format); | 65 va_start(arglist, format); |
| 65 vprintf(format, arglist); | 66 vprintf(format, arglist); |
| 66 va_end(arglist); | 67 va_end(arglist); |
| 67 } | 68 } |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 215 double ticks_per_column_exact = | 216 double ticks_per_column_exact = |
| 216 static_cast<double>(num_ticks) / static_cast<double>(terminal_width); | 217 static_cast<double>(num_ticks) / static_cast<double>(terminal_width); |
| 217 int ticks_per_column = std::ceil(ticks_per_column_exact); | 218 int ticks_per_column = std::ceil(ticks_per_column_exact); |
| 218 DCHECK_GE(ticks_per_column * terminal_width, num_ticks); | 219 DCHECK_GE(ticks_per_column * terminal_width, num_ticks); |
| 219 | 220 |
| 220 // Sum up the column values. | 221 // Sum up the column values. |
| 221 int num_columns = num_ticks / ticks_per_column; | 222 int num_columns = num_ticks / ticks_per_column; |
| 222 if (num_ticks % ticks_per_column) | 223 if (num_ticks % ticks_per_column) |
| 223 ++num_columns; | 224 ++num_columns; |
| 224 DCHECK_LE(num_columns, terminal_width); | 225 DCHECK_LE(num_columns, terminal_width); |
| 225 scoped_ptr<int[]> columns(new int[num_columns]); | 226 std::unique_ptr<int[]> columns(new int[num_columns]); |
| 226 for (int tx = 0; tx < num_ticks; ++tx) { | 227 for (int tx = 0; tx < num_ticks; ++tx) { |
| 227 int cx = tx / ticks_per_column; | 228 int cx = tx / ticks_per_column; |
| 228 if (tx % ticks_per_column == 0) | 229 if (tx % ticks_per_column == 0) |
| 229 columns[cx] = 0; | 230 columns[cx] = 0; |
| 230 columns[cx] += requests_per_tick_[tx]; | 231 columns[cx] += requests_per_tick_[tx]; |
| 231 } | 232 } |
| 232 | 233 |
| 233 // Find the lowest integer divisor that will let the column values | 234 // Find the lowest integer divisor that will let the column values |
| 234 // be represented in a graph of maximum height 50. | 235 // be represented in a graph of maximum height 50. |
| 235 int max_value = 0; | 236 int max_value = 0; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 286 TimeTicks end_downtime_; | 287 TimeTicks end_downtime_; |
| 287 const int max_queries_per_tick_; | 288 const int max_queries_per_tick_; |
| 288 const double request_drop_ratio_; // Ratio of requests to 503 when failing. | 289 const double request_drop_ratio_; // Ratio of requests to 503 when failing. |
| 289 int num_overloaded_ticks_remaining_; | 290 int num_overloaded_ticks_remaining_; |
| 290 int num_current_tick_queries_; | 291 int num_current_tick_queries_; |
| 291 int num_overloaded_ticks_; | 292 int num_overloaded_ticks_; |
| 292 int max_experienced_queries_per_tick_; | 293 int max_experienced_queries_per_tick_; |
| 293 std::vector<int> requests_per_tick_; | 294 std::vector<int> requests_per_tick_; |
| 294 | 295 |
| 295 TestURLRequestContext context_; | 296 TestURLRequestContext context_; |
| 296 scoped_ptr<URLRequest> mock_request_; | 297 std::unique_ptr<URLRequest> mock_request_; |
| 297 | 298 |
| 298 DISALLOW_COPY_AND_ASSIGN(Server); | 299 DISALLOW_COPY_AND_ASSIGN(Server); |
| 299 }; | 300 }; |
| 300 | 301 |
| 301 // Mock throttler entry used by Requester class. | 302 // Mock throttler entry used by Requester class. |
| 302 class MockExtensionThrottleEntry : public ExtensionThrottleEntry { | 303 class MockExtensionThrottleEntry : public ExtensionThrottleEntry { |
| 303 public: | 304 public: |
| 304 explicit MockExtensionThrottleEntry(ExtensionThrottleManager* manager) | 305 explicit MockExtensionThrottleEntry(ExtensionThrottleManager* manager) |
| 305 : ExtensionThrottleEntry(manager, std::string()), | 306 : ExtensionThrottleEntry(manager, std::string()), |
| 306 backoff_entry_(&backoff_policy_, &fake_clock_) {} | 307 backoff_entry_(&backoff_policy_, &fake_clock_) {} |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 482 }; | 483 }; |
| 483 | 484 |
| 484 void SimulateAttack(Server* server, | 485 void SimulateAttack(Server* server, |
| 485 RequesterResults* attacker_results, | 486 RequesterResults* attacker_results, |
| 486 RequesterResults* client_results, | 487 RequesterResults* client_results, |
| 487 bool enable_throttling) { | 488 bool enable_throttling) { |
| 488 const size_t kNumAttackers = 50; | 489 const size_t kNumAttackers = 50; |
| 489 const size_t kNumClients = 50; | 490 const size_t kNumClients = 50; |
| 490 DiscreteTimeSimulation simulation; | 491 DiscreteTimeSimulation simulation; |
| 491 ExtensionThrottleManager manager; | 492 ExtensionThrottleManager manager; |
| 492 std::vector<scoped_ptr<Requester>> requesters; | 493 std::vector<std::unique_ptr<Requester>> requesters; |
| 493 for (size_t i = 0; i < kNumAttackers; ++i) { | 494 for (size_t i = 0; i < kNumAttackers; ++i) { |
| 494 // Use a tiny time_between_requests so the attackers will ping the | 495 // Use a tiny time_between_requests so the attackers will ping the |
| 495 // server at every tick of the simulation. | 496 // server at every tick of the simulation. |
| 496 scoped_refptr<MockExtensionThrottleEntry> throttler_entry( | 497 scoped_refptr<MockExtensionThrottleEntry> throttler_entry( |
| 497 new MockExtensionThrottleEntry(&manager)); | 498 new MockExtensionThrottleEntry(&manager)); |
| 498 if (!enable_throttling) | 499 if (!enable_throttling) |
| 499 throttler_entry->DisableBackoffThrottling(); | 500 throttler_entry->DisableBackoffThrottling(); |
| 500 | 501 |
| 501 Requester* attacker = | 502 Requester* attacker = |
| 502 new Requester(throttler_entry.get(), TimeDelta::FromMilliseconds(1), | 503 new Requester(throttler_entry.get(), TimeDelta::FromMilliseconds(1), |
| 503 server, attacker_results); | 504 server, attacker_results); |
| 504 attacker->SetStartupJitter(TimeDelta::FromSeconds(120)); | 505 attacker->SetStartupJitter(TimeDelta::FromSeconds(120)); |
| 505 requesters.push_back(make_scoped_ptr(attacker)); | 506 requesters.push_back(base::WrapUnique(attacker)); |
| 506 simulation.AddActor(attacker); | 507 simulation.AddActor(attacker); |
| 507 } | 508 } |
| 508 for (size_t i = 0; i < kNumClients; ++i) { | 509 for (size_t i = 0; i < kNumClients; ++i) { |
| 509 // Normal clients only make requests every 2 minutes, plus/minus 1 minute. | 510 // Normal clients only make requests every 2 minutes, plus/minus 1 minute. |
| 510 scoped_refptr<MockExtensionThrottleEntry> throttler_entry( | 511 scoped_refptr<MockExtensionThrottleEntry> throttler_entry( |
| 511 new MockExtensionThrottleEntry(&manager)); | 512 new MockExtensionThrottleEntry(&manager)); |
| 512 if (!enable_throttling) | 513 if (!enable_throttling) |
| 513 throttler_entry->DisableBackoffThrottling(); | 514 throttler_entry->DisableBackoffThrottling(); |
| 514 | 515 |
| 515 Requester* client = | 516 Requester* client = |
| 516 new Requester(throttler_entry.get(), TimeDelta::FromMinutes(2), server, | 517 new Requester(throttler_entry.get(), TimeDelta::FromMinutes(2), server, |
| 517 client_results); | 518 client_results); |
| 518 client->SetStartupJitter(TimeDelta::FromSeconds(120)); | 519 client->SetStartupJitter(TimeDelta::FromSeconds(120)); |
| 519 client->SetRequestJitter(TimeDelta::FromMinutes(1)); | 520 client->SetRequestJitter(TimeDelta::FromMinutes(1)); |
| 520 requesters.push_back(make_scoped_ptr(client)); | 521 requesters.push_back(base::WrapUnique(client)); |
| 521 simulation.AddActor(client); | 522 simulation.AddActor(client); |
| 522 } | 523 } |
| 523 simulation.AddActor(server); | 524 simulation.AddActor(server); |
| 524 | 525 |
| 525 simulation.RunSimulation(TimeDelta::FromMinutes(6), | 526 simulation.RunSimulation(TimeDelta::FromMinutes(6), |
| 526 TimeDelta::FromSeconds(1)); | 527 TimeDelta::FromSeconds(1)); |
| 527 } | 528 } |
| 528 | 529 |
| 529 TEST(URLRequestThrottlerSimulation, HelpsInAttack) { | 530 TEST(URLRequestThrottlerSimulation, HelpsInAttack) { |
| 530 base::MessageLoopForIO message_loop; | 531 base::MessageLoopForIO message_loop; |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 736 trials[i].PrintTrialDescription(); | 737 trials[i].PrintTrialDescription(); |
| 737 trials[i].stats.ReportTrialResult(increase_ratio); | 738 trials[i].stats.ReportTrialResult(increase_ratio); |
| 738 } | 739 } |
| 739 | 740 |
| 740 VerboseOut("Average increase ratio was %.4f\n", average_increase_ratio); | 741 VerboseOut("Average increase ratio was %.4f\n", average_increase_ratio); |
| 741 VerboseOut("Maximum increase ratio was %.4f\n", max_increase_ratio); | 742 VerboseOut("Maximum increase ratio was %.4f\n", max_increase_ratio); |
| 742 } | 743 } |
| 743 | 744 |
| 744 } // namespace | 745 } // namespace |
| 745 } // namespace extensions | 746 } // namespace extensions |
| OLD | NEW |