diff --git a/README.md b/README.md index 4a355c5a..d2d4bdc5 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ The current version offers the following features : * Support for aliases/redirection. * Support for switch the site to a maintenance page only. * Support for URL traffic based throttling (experimental). - * Support for overriden of error messages by local document (ErrorDocument/40x|500.html). + * Support for overriden of error messages by local document (ex. ErrorDocument/400.html). * Support for RewriteRule (lighttpd-like) that check for file existence as they do on Apache, some CMS (SilverStripe) require it. * Support for (apache-like) log [NCSA extended/combined format](http://httpd.apache.org/docs/2.0/mod/mod_log_config.html) * Support for [JSONRequest](http://json.org/JSONRequest.html). @@ -69,6 +69,7 @@ The current version offers the following features : * [DNS rebinding](http://en.wikipedia.org/wiki/DNS_rebinding) prevention by RFC1918 filtering and Host header validation. * selective uri support (DOS regex) for [HTTP Strict Transport Security](https://developer.mozilla.org/en/Security/HTTP_Strict_Transport_Security). * Immune to [Slow Read DoS attack](http://code.google.com/p/slowhttptest/) + * Provide evasive action in the event of an HTTP DoS or DDoS attack or brute force attack. * [High SSL server quality score](https://www.ssllabs.com/ssltest/analyze.html?d=wifi-aaa2.comune.fi.it) ## Who is Using ULib diff --git a/configure b/configure index d3f60b4e..68eabeef 100755 --- a/configure +++ b/configure @@ -1050,6 +1050,7 @@ enable_http2 enable_check_time enable_classic enable_throttling +enable_evasive enable_alias enable_welcome enable_ACL @@ -1793,6 +1794,7 @@ Optional Features: --enable-check-time enable server check time between request for parallelization [default=no] --enable-classic enable server classic model support [default=no] --enable-throttling enable server bandwidth throttling support [default=no] + --enable-evasive enable server evasive action support [default=no] --enable-alias enable alias URI support [default=yes] --enable-welcome enable welcome message support [default=no] --enable-ACL enable ACL filtering support [default=no] @@ -26478,6 +26480,24 @@ $as_echo "#define U_THROTTLING_SUPPORT 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_throttling" >&5 $as_echo "$enable_throttling" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if you want to enable to provide evasive action in the event of an HTTP DoS or DDoS attack or brute force attack" >&5 +$as_echo_n "checking if you want to enable to provide evasive action in the event of an HTTP DoS or DDoS attack or brute force attack... " >&6; } + # Check whether --enable-evasive was given. +if test "${enable_evasive+set}" = set; then : + enableval=$enable_evasive; +fi + + if test -z "$enable_evasive"; then + enable_evasive="no" + fi + if test "$enable_evasive" = "yes"; then + +$as_echo "#define U_EVASIVE_SUPPORT 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_evasive" >&5 +$as_echo "$enable_evasive" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if you want to enable alias URI support" >&5 $as_echo_n "checking if you want to enable alias URI support... " >&6; } # Check whether --enable-alias was given. @@ -32849,17 +32869,20 @@ if test "x$ac_cv_crc32_intrinsics" = xyes; then esac fi fi +########################## if test "$ac_cv_c_compiler_gnu" = "yes" -a "x$GCC_IS_CLANG" = xno; then if test "$enable_static" = "yes" -a "$enable_shared" = "no" -a "$enable_stdcpp" = "yes"; then - gcc_lib=`gcc -print-libgcc-file-name` - gcc_dir=`dirname $gcc_lib` - if test -f "$gcc_dir/libstdc++.a"; then - ULIB_LIBS="$ULIB_LIBS $gcc_dir/libstdc++.a $gcc_lib" - else - ULIB_LIBS="$ULIB_LIBS -lstdc++ -lgcc" - fi +## if test -f "$gcc_dir/libstdc++.a"; then +## gcc_lib=`gcc -print-libgcc-file-name` +## gcc_dir=`dirname $gcc_lib` +## ULIB_LIBS="$ULIB_LIBS $gcc_dir/libstdc++.a $gcc_lib" +## else +## ULIB_LIBS="$ULIB_LIBS -lstdc++ -lgcc" +## fi + + ULIB_LIBS="$ULIB_LIBS -lstdc++ -lgcc" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use libgcc" >&5 $as_echo_n "checking whether to use libgcc... " >&6; } @@ -32883,7 +32906,6 @@ fi fi fi -########################## # Check for availablity of "old style" C++ strstream header for ac_header in strstream.h diff --git a/configure.ac b/configure.ac index 809b1e8e..9e462002 100644 --- a/configure.ac +++ b/configure.ac @@ -2541,17 +2541,20 @@ if test "x$ac_cv_crc32_intrinsics" = xyes; then esac fi fi +########################## if test "$ac_cv_c_compiler_gnu" = "yes" -a "x$GCC_IS_CLANG" = xno; then if test "$enable_static" = "yes" -a "$enable_shared" = "no" -a "$enable_stdcpp" = "yes"; then - gcc_lib=`gcc -print-libgcc-file-name` - gcc_dir=`dirname $gcc_lib` - if test -f "$gcc_dir/libstdc++.a"; then - ULIB_LIBS="$ULIB_LIBS $gcc_dir/libstdc++.a $gcc_lib" - else - ULIB_LIBS="$ULIB_LIBS -lstdc++ -lgcc" - fi +## if test -f "$gcc_dir/libstdc++.a"; then +## gcc_lib=`gcc -print-libgcc-file-name` +## gcc_dir=`dirname $gcc_lib` +## ULIB_LIBS="$ULIB_LIBS $gcc_dir/libstdc++.a $gcc_lib" +## else +## ULIB_LIBS="$ULIB_LIBS -lstdc++ -lgcc" +## fi + + ULIB_LIBS="$ULIB_LIBS -lstdc++ -lgcc" else AC_MSG_CHECKING([whether to use libgcc]) AC_ARG_ENABLE(libgcc, @@ -2568,7 +2571,6 @@ if test "$ac_cv_c_compiler_gnu" = "yes" -a "x$GCC_IS_CLANG" = xno; then ) fi fi -########################## # Check for availablity of "old style" C++ strstream header AC_CHECK_HEADERS([strstream.h]) diff --git a/examples/userver/userver.cfg.default b/examples/userver/userver.cfg.default index 11d805af..1d00bdad 100644 --- a/examples/userver/userver.cfg.default +++ b/examples/userver/userver.cfg.default @@ -71,6 +71,17 @@ # # if PREFORK_CHILD is not defined is as case (>1) with num process the number of CPU in the system # ---------------------------------------------------------------------------------------------------------------------------------------- +# This directive are for evasive action in the event of an HTTP DoS or DDoS attack or brute force attack +# ---------------------------------------------------------------------------------------------------------------------------------------- +# DOS_PAGE_COUNT this is the threshhold for the number of requests for the same page (or URI) per page interval +# DOS_PAGE_INTERVAL the interval for the page count threshhold; defaults to 1 second intervals +# DOS_SITE_COUNT this is the threshhold for the total number of requests for any object by the same client per site interval +# DOS_SITE_INTERVAL the interval for the site count threshhold; defaults to 1 second intervals +# DOS_BLOCKING_PERIOD the blocking period is the amount of time (in seconds) that a client will be blocked for if they are added to the blocking list (defaults to 10) +# DOS_WHITE_LIST list of comma separated IP addresses of trusted clients can be whitelisted to insure they are never denied (IPADDR[/MASK]) +# DOS_EMAIL_NOTIFY the email address to send a message whenever an IP address becomes blacklisted +# DOS_SYSTEM_COMMAND the system command specified will be executed whenever an IP address becomes blacklisted. Use %v to denote the IP address of the blacklisted IP +# ---------------------------------------------------------------------------------------------------------------------------------------- userver { diff --git a/examples/userver/userver.cpp b/examples/userver/userver.cpp index 75e703e6..62388e47 100644 --- a/examples/userver/userver.cpp +++ b/examples/userver/userver.cpp @@ -117,6 +117,17 @@ public: // 1 - classic, forking after accept client) // >1 - pool of process serialize plus monitoring process) // --------------------------------------------------------------------------------------------------------------------------------------- + // This directive are for evasive action in the event of an HTTP DoS or DDoS attack or brute force attack + // --------------------------------------------------------------------------------------------------------------------------------------- + // DOS_PAGE_COUNT this is the threshhold for the number of requests for the same page (or URI) per page interval + // DOS_PAGE_INTERVAL the interval for the page count threshhold; defaults to 1 second intervals + // DOS_SITE_COUNT this is the threshhold for the total number of requests for any object by the same client per site interval + // DOS_SITE_INTERVAL the interval for the site count threshhold; defaults to 1 second intervals + // DOS_BLOCKING_PERIOD the blocking period is the amount of time (in seconds) that a client will be blocked for if they are added to the blocking list (defaults to 10) + // DOS_WHITE_LIST list of comma separated IP addresses of trusted clients can be whitelisted to insure they are never denied (IPADDR[/MASK]) + // DOS_EMAIL_NOTIFY the email address to send a message whenever an IP address becomes blacklisted + // DOS_SYSTEM_COMMAND the system command specified will be executed whenever an IP address becomes blacklisted. Use %v to denote the IP address of the blacklisted IP + // --------------------------------------------------------------------------------------------------------------------------------------- # ifdef U_SSL_SOCKET UServer_Base::bssl = true; diff --git a/examples/workflow/validation.cpp b/examples/workflow/validation.cpp index 257fb2ea..80bf5daf 100644 --- a/examples/workflow/validation.cpp +++ b/examples/workflow/validation.cpp @@ -40,6 +40,7 @@ public: if (subject == U_NOT_FOUND) U_ERROR("cannot find mail header subject on input data"); + // ---------------------------------------------------------------------------------------------------------------------------- // scanf mail header Subject: from request // ---------------------------------------------------------------------------------------------------------------------------- // "Subject: %*[^"]\"%[^"]\", %*[^"]\"%[^"]\", %*[^"]\"%[^"]\"" diff --git a/include/ulib/application.h b/include/ulib/application.h index d646e94c..0570e6e2 100644 --- a/include/ulib/application.h +++ b/include/ulib/application.h @@ -19,13 +19,13 @@ #define U_PRINT_MEM_USAGE #ifdef DEBUG -#define U_MAIN_END(value) return value +# define U_MAIN_END(value) return value # ifdef U_STDCPP_ENABLE # undef U_PRINT_MEM_USAGE # define U_PRINT_MEM_USAGE UApplication::printMemUsage(); # endif #else -#define U_MAIN_END(value) ::exit(value) +# define U_MAIN_END(value) ::exit(value) #endif #define U_MAIN \ diff --git a/include/ulib/base/utility.h b/include/ulib/base/utility.h index dc0ca273..caf4d72e 100644 --- a/include/ulib/base/utility.h +++ b/include/ulib/base/utility.h @@ -205,6 +205,9 @@ static inline uint32_t u_findEndHeader1(const char* restrict s, uint32_t n) /* f U_INTERNAL_TRACE("u_findEndHeader1(%.*s,%u)", U_min(n,128), s, n) U_INTERNAL_ASSERT_POINTER(s) + U_INTERNAL_ASSERT_MAJOR(n, 0) + + if (u_get_unalignedp32(s+n-4) == U_MULTICHAR_CONSTANT32('\r','\n','\r','\n')) return (n-4); p = memmem(s, n, U_CONSTANT_TO_PARAM(U_CRLF2)); diff --git a/include/ulib/db/rdb.h b/include/ulib/db/rdb.h index 2a6e2b0e..867c14a7 100644 --- a/include/ulib/db/rdb.h +++ b/include/ulib/db/rdb.h @@ -472,22 +472,9 @@ public: return _insertDataStorage(op); } - bool insertDataStorage(const UString& _key, int _flag = RDB_INSERT_WITH_PADDING) + bool insertDataStorage(const char* s, uint32_t n, int _flag = RDB_INSERT) // SSL session cache... { - U_TRACE(0, "URDBObjectHandler::insertDataStorage(%V,%d)", _key.rep, _flag) - - U_CHECK_MEMORY - - U_INTERNAL_ASSERT_POINTER(pDataStorage) - - pDataStorage->setKeyIdDataSession(_key); - - return insertDataStorage(_flag); - } - - void insertDataStorage(const char* s, uint32_t n) - { - U_TRACE(0, "URDBObjectHandler::insertDataStorage(%.*S,%u)", n, s, n) + U_TRACE(0, "URDBObjectHandler::insertDataStorage(%.*S,%u,%d)", n, s, n, _flag) U_CHECK_MEMORY @@ -495,7 +482,14 @@ public: pDataStorage->setKeyIdDataSession(s, n); - (void) insertDataStorage(RDB_INSERT); // SSL session cache... + return insertDataStorage(_flag); + } + + bool insertDataStorage(const UString& _key, int _flag = RDB_INSERT_WITH_PADDING) + { + U_TRACE(0, "URDBObjectHandler::insertDataStorage(%V,%d)", _key.rep, _flag) + + return insertDataStorage(U_STRING_TO_PARAM(_key), _flag); } UString getKeyID() const { return pDataStorage->keyid; } diff --git a/include/ulib/internal/chttp.h b/include/ulib/internal/chttp.h index 9168533e..3f64d940 100644 --- a/include/ulib/internal/chttp.h +++ b/include/ulib/internal/chttp.h @@ -145,6 +145,19 @@ typedef struct uhttpinfo { unsigned char flag[16]; } uhttpinfo; +/** + * GET is used to retrieve a resource on the server. + * HEAD is used to retrieve some information about the document, but don't need the document itself. + * POST says that you are providing some information of your own (i.e., in forms). This may change the state of the server in some way, such as creating a record in a database. + * PUT is used to replace or create a new document on the server. + * DELETE is used to remove a document on the server. + * TRACE is used for protocol debugging purposes. + * OPTIONS is used when the client looks for other methods which can be used on the document. + * CONNECT is used when a client needs to talk to an HTTPS server through a proxy server. + * + * Other HTTP methods that you may see (LINK, UNLINK, and PATCH) are less clearly defined + */ + enum HTTPMethodType { /* request methods */ HTTP_GET = 0x00000001, diff --git a/include/ulib/internal/common.h b/include/ulib/internal/common.h index 5b935b0b..f528670d 100644 --- a/include/ulib/internal/common.h +++ b/include/ulib/internal/common.h @@ -144,7 +144,7 @@ union uustringrep { ustringrep* p1; UStringRep* p2; }; class U_EXPORT ULib { public: ULib(const char* mempool) { init(mempool, U_NULLPTR); } - ~ULib() { end(); } + ~ULib() { end(); } static void end(); static void init(const char* mempool, char** argv); diff --git a/include/ulib/internal/config.h.in b/include/ulib/internal/config.h.in index 03101507..1b393489 100644 --- a/include/ulib/internal/config.h.in +++ b/include/ulib/internal/config.h.in @@ -808,6 +808,9 @@ /* enable client response partial write support */ #undef U_CLIENT_RESPONSE_PARTIAL_WRITE_SUPPORT +/* enable server evasive action support */ +#undef U_EVASIVE_SUPPORT + /* enable GDB stack dump support */ #undef U_GDB_STACK_DUMP_ENABLE diff --git a/include/ulib/net/server/server.h b/include/ulib/net/server/server.h index b12d8550..6cb7a646 100644 --- a/include/ulib/net/server/server.h +++ b/include/ulib/net/server/server.h @@ -98,6 +98,7 @@ vClientImage = new client_type[UNotifier::max_connection]; } } class UHTTP; class UHTTP2; class UCommand; +class UEvasive; class UDayLight; class UTimeStat; class USSLSocket; @@ -111,6 +112,7 @@ class UHttpPlugIn; class UFCGIPlugIn; class USCGIPlugIn; class UThrottling; +class USmtpClient; class UNoCatPlugIn; class UGeoIPPlugIn; class UClient_Base; @@ -136,9 +138,9 @@ public: U_MEMORY_ALLOCATOR U_MEMORY_DEALLOCATOR - // ----------------------------------------------------------------------------------------------------------------------------- + // -------------------------------------------------------------------------------------------------------------------------------------- // UServer - configuration parameters - // ----------------------------------------------------------------------------------------------------------------------------- + // -------------------------------------------------------------------------------------------------------------------------------------- // ENABLE_IPV6 flag indicating the use of ipv6 // SERVER host name or ip address for the listening socket // PORT port number for the listening socket @@ -189,7 +191,18 @@ public: // PREFORK_CHILD number of child server processes created at startup ( 0 - serialize, no forking // 1 - classic, forking after client accept // >1 - pool of serialized processes plus monitoring process) - // ----------------------------------------------------------------------------------------------------------------------------- + // -------------------------------------------------------------------------------------------------------------------------------------- + // This directive are for evasive action in the event of an HTTP DoS or DDoS attack or brute force attack + // -------------------------------------------------------------------------------------------------------------------------------------- + // DOS_PAGE_COUNT this is the threshhold for the number of requests for the same page (or URI) per page interval + // DOS_PAGE_INTERVAL the interval for the page count threshhold; defaults to 1 second intervals + // DOS_SITE_COUNT this is the threshhold for the total number of requests for any object by the same client per site interval + // DOS_SITE_INTERVAL the interval for the site count threshhold; defaults to 1 second intervals + // DOS_BLOCKING_PERIOD the blocking period is the amount of time (in seconds) that a client will be blocked for if they are added to the blocking list (defaults to 10) + // DOS_WHITE_LIST list of comma separated IP addresses of trusted clients can be whitelisted to insure they are never denied (IPADDR[/MASK]) + // DOS_EMAIL_NOTIFY the email address to send a message whenever an IP address becomes blacklisted + // DOS_SYSTEM_COMMAND the system command specified will be executed whenever an IP address becomes blacklisted. Use %v to denote the IP address of the blacklisted IP + // -------------------------------------------------------------------------------------------------------------------------------------- static void run(); // loop waiting for connection @@ -225,9 +238,6 @@ public: static void setMsgWelcome(const UString& msg); #endif -#if defined(U_LINUX) && defined(ENABLE_THREAD) -#endif - // ------------------------------------------------------------------- // MANAGE PLUGIN MODULES // ------------------------------------------------------------------- @@ -283,7 +293,7 @@ public: char buffer4[512]; char buffer5[512]; char buffer6[512]; - char buffer7[431]; + char buffer7[402]; // --------------------------------- uint8_t flag_sigterm; // --------------------------------- @@ -296,12 +306,14 @@ public: // --------------------------------- sem_t lock_user1; sem_t lock_user2; + sem_t lock_evasive; sem_t lock_throttling; sem_t lock_rdb_server; sem_t lock_data_session; sem_t lock_db_not_found; char spinlock_user1[1]; char spinlock_user2[1]; + char spinlock_evasive[1]; char spinlock_throttling[1]; char spinlock_rdb_server[1]; char spinlock_data_session[1]; @@ -353,6 +365,7 @@ public: #define U_SRV_CNT_PARALLELIZATION UServer_Base::ptr_shared_data->cnt_parallelization #define U_SRV_LOCK_USER1 &(UServer_Base::ptr_shared_data->lock_user1) #define U_SRV_LOCK_USER2 &(UServer_Base::ptr_shared_data->lock_user2) +#define U_SRV_LOCK_EVASIVE &(UServer_Base::ptr_shared_data->lock_evasive) #define U_SRV_LOCK_THROTTLING &(UServer_Base::ptr_shared_data->lock_throttling) #define U_SRV_LOCK_RDB_SERVER &(UServer_Base::ptr_shared_data->lock_rdb_server) #define U_SRV_LOCK_SSL_SESSION &(UServer_Base::ptr_shared_data->lock_ssl_session) @@ -360,6 +373,7 @@ public: #define U_SRV_LOCK_DB_NOT_FOUND &(UServer_Base::ptr_shared_data->lock_db_not_found) #define U_SRV_SPINLOCK_USER1 UServer_Base::ptr_shared_data->spinlock_user1 #define U_SRV_SPINLOCK_USER2 UServer_Base::ptr_shared_data->spinlock_user2 +#define U_SRV_SPINLOCK_EVASIVE UServer_Base::ptr_shared_data->spinlock_evasive #define U_SRV_SPINLOCK_THROTTLING UServer_Base::ptr_shared_data->spinlock_throttling #define U_SRV_SPINLOCK_RDB_SERVER UServer_Base::ptr_shared_data->spinlock_rdb_server #define U_SRV_SPINLOCK_SSL_SESSION UServer_Base::ptr_shared_data->spinlock_ssl_session @@ -633,6 +647,24 @@ protected: static void initThrottlingServer(); #endif +#ifdef U_EVASIVE_SUPPORT // provide evasive action in the event of an HTTP DoS or DDoS attack or brute force attack + static bool bwhitelist; + static UString* emailAddress; + static UString* whitelist_IP; + static UEvasive* evasive_rec; + static UString* systemCommand; + static USmtpClient* emailClient; + static UVector* vwhitelist_IP; + static URDBObjectHandler* db_evasive; + static uint32_t blocking_period, page_interval, page_count, site_interval, site_count; + + static void initEvasive(); + static bool checkHitUriStats(); + static bool checkHitSiteStats(); + static bool checkHitStats(const char* key, uint32_t key_len, uint32_t interval, uint32_t count); + static bool checkHold(in_addr_t client, const char* client_address, uint32_t client_address_len); +#endif + UServer_Base(UFileConfig* pcfg = U_NULLPTR); virtual ~UServer_Base(); @@ -716,6 +748,7 @@ private: friend class UHTTP; friend class UHTTP2; + friend class UEvasive; friend class UDayLight; friend class UTimeStat; friend class USSLSocket; diff --git a/include/ulib/utility/uhttp.h b/include/ulib/utility/uhttp.h index 8539a12e..66e21193 100644 --- a/include/ulib/utility/uhttp.h +++ b/include/ulib/utility/uhttp.h @@ -204,10 +204,40 @@ public: static bool scanfHeaderRequest(const char* ptr, uint32_t size); static bool scanfHeaderResponse(const char* ptr, uint32_t size); static bool readHeaderResponse(USocket* socket, UString& buffer); - static bool isValidRequest( const char* ptr, uint32_t size) __pure; - static bool isValidRequestExt(const char* ptr, uint32_t size) __pure; static bool readBodyResponse(USocket* socket, UString* buffer, UString& body); + static bool isValidRequest(const char* ptr, uint32_t sz) + { + U_TRACE(0, "UHTTP::isValidRequest(%.*S,%u)", 30, ptr, sz) + + U_INTERNAL_ASSERT_MAJOR(sz, 0) + + U_INTERNAL_DUMP("sz = %u UClientImage_Base::size_request = %u", sz, UClientImage_Base::size_request) + + if (u_get_unalignedp32(ptr+sz-4) == U_MULTICHAR_CONSTANT32('\r','\n','\r','\n')) U_RETURN(true); + + U_RETURN(false); + } + + static bool isValidRequestExt(const char* ptr, uint32_t sz) + { + U_TRACE(0, "UHTTP::isValidRequestExt(%.*S,%u)", 30, ptr, sz) + + U_INTERNAL_ASSERT_MAJOR(sz, 0) + + if (sz >= U_CONSTANT_SIZE("GET / HTTP/1.0\r\n\r\n") && + isValidMethod(ptr) && + (isValidRequest(ptr, sz) || + (UClientImage_Base::size_request && + isValidRequest(ptr, UClientImage_Base::size_request)) || + memmem(ptr, sz, U_CONSTANT_TO_PARAM(U_CRLF2)) != U_NULLPTR)) + { + U_RETURN(true); + } + + U_RETURN(false); + } + #ifndef U_HTTP2_DISABLE static bool copyHeaders(UStringRep* key, void* elem); static bool upgradeHeaders(UStringRep* key, void* elem) diff --git a/m4/ac_compilation_options.m4 b/m4/ac_compilation_options.m4 index eb46648b..d389c017 100644 --- a/m4/ac_compilation_options.m4 +++ b/m4/ac_compilation_options.m4 @@ -247,6 +247,17 @@ AC_DEFUN([AC_COMPILATION_OPTIONS],[ fi AC_MSG_RESULT([$enable_throttling]) + AC_MSG_CHECKING(if you want to enable to provide evasive action in the event of an HTTP DoS or DDoS attack or brute force attack) + AC_ARG_ENABLE(evasive, + [ --enable-evasive enable server evasive action support [[default=no]]]) + if test -z "$enable_evasive"; then + enable_evasive="no" + fi + if test "$enable_evasive" = "yes"; then + AC_DEFINE(U_EVASIVE_SUPPORT, 1, [enable server evasive action support]) + fi + AC_MSG_RESULT([$enable_evasive]) + AC_MSG_CHECKING(if you want to enable alias URI support) AC_ARG_ENABLE(alias, [ --enable-alias enable alias URI support [[default=yes]]]) diff --git a/src/ulib/application.cpp b/src/ulib/application.cpp index ef0d10f8..80a19355 100644 --- a/src/ulib/application.cpp +++ b/src/ulib/application.cpp @@ -65,7 +65,7 @@ void UApplication::printMemUsage() UServer_Base::getStats().rep, (double)vsz / (1024.0 * 1024.0), (double)rss / (1024.0 * 1024.0), UNotifier::max_nfd_ready, UServer_Base::max_depth, UServer_Base::nread_again, UServer_Base::nread, - (UServer_Base::nread_again * 100) / UServer_Base::nread, UServer_Base::wakeup_for_nothing, UNotifier::bepollet_threshold); + (UServer_Base::nread_again * 100) / (UServer_Base::nread ? UServer_Base::nread : 1), UServer_Base::wakeup_for_nothing, UNotifier::bepollet_threshold); ostrstream os(buffer + len, sizeof(buffer) - len); diff --git a/src/ulib/internal/common.cpp b/src/ulib/internal/common.cpp index 852e69f9..8dbe8865 100644 --- a/src/ulib/internal/common.cpp +++ b/src/ulib/internal/common.cpp @@ -312,7 +312,6 @@ void ULib::init(const char* mempool, char** argv) void ULib::end() { - #if defined(U_STDCPP_ENABLE) && defined(DEBUG) UApplication::printMemUsage(); #endif diff --git a/src/ulib/net/client/smtp.cpp b/src/ulib/net/client/smtp.cpp index 4ed93646..4ac7e37a 100644 --- a/src/ulib/net/client/smtp.cpp +++ b/src/ulib/net/client/smtp.cpp @@ -58,9 +58,7 @@ bool USmtpClient::_connectServer(const UString& server, unsigned int port, int t U_INTERNAL_ASSERT_EQUALS(u_buffer_len, 0) - // NB: the last argument (0) is necessary... - - u_buffer_len = u__snprintf(u_buffer, U_BUFFER_SIZE, U_CONSTANT_TO_PARAM("Sorry, couldn't connect to server '%v:%u'%R"), server.rep, port, 0); + u_buffer_len = u__snprintf(u_buffer,U_BUFFER_SIZE,U_CONSTANT_TO_PARAM("Sorry, couldn't connect to server '%v:%u'%R"),server.rep,port,0); // NB: the last argument (0) is necessary... } else { @@ -91,6 +89,7 @@ bool USmtpClient::_connectServer(UFileConfig& cfg, unsigned int port, int timeou U_ASSERT_EQUALS(cfg.empty(), false) + // ---------------------------------------------------------------------------------------------------------------------- // USmtpClient - configuration parameters // ---------------------------------------------------------------------------------------------------------------------- // SMTP_SERVER host name or ip address for server diff --git a/src/ulib/net/rpc/rpc_client.cpp b/src/ulib/net/rpc/rpc_client.cpp index 89bdfb2a..e292d63b 100644 --- a/src/ulib/net/rpc/rpc_client.cpp +++ b/src/ulib/net/rpc/rpc_client.cpp @@ -31,7 +31,7 @@ bool URPCClient_Base::readResponse(USocket* sk, UString& buffer, UString& respon buffer.size_adjust_force(U_TOKEN_NM); } - U_INTERNAL_DUMP("buffer = %V response = %V)", buffer.rep, response.rep) + U_INTERNAL_DUMP("buffer = %V response = %V", buffer.rep, response.rep) if (buffer) U_RETURN(true); diff --git a/src/ulib/net/server/client_image.cpp b/src/ulib/net/server/client_image.cpp index 89149303..abaa480e 100644 --- a/src/ulib/net/server/client_image.cpp +++ b/src/ulib/net/server/client_image.cpp @@ -944,6 +944,15 @@ void UClientImage_Base::prepareForRead() UServer_Base::client_address_len = u__strlen(UServer_Base::client_address, __PRETTY_FUNCTION__); U_INTERNAL_DUMP("UServer_Base::client_address = %.*S", U_CLIENT_ADDRESS_TO_TRACE) + +# ifdef U_EVASIVE_SUPPORT + if (UServer_Base::checkHold(socket->remoteIPAddress().getInAddr(), U_CLIENT_ADDRESS_TO_PARAM)) + { + abortive_close(); + + return; + } +# endif } else { @@ -959,6 +968,10 @@ void UClientImage_Base::prepareForRead() UEventFd::fd = socket->iSockDesc; } +#ifdef U_EVASIVE_SUPPORT + if (UServer_Base::checkHitSiteStats()) return; +#endif + #ifdef U_THROTTLING_SUPPORT UServer_Base::initThrottlingClient(); #endif @@ -968,15 +981,17 @@ bool UClientImage_Base::genericRead() { U_TRACE_NO_PARAM(0, "UClientImage_Base::genericRead()") -#ifdef DEBUG +#if defined(DEBUG) || defined(U_EVASIVE_SUPPORT) if (UNLIKELY(socket->iSockDesc == -1)) { +# ifndef U_EVASIVE_SUPPORT U_WARNING("genericRead(): " "UEventFd::fd = %d socket->iSockDesc = %d " "UNotifier::num_connection = %d UNotifier::min_connection = %d " "UServer_Base::isParallelizationChild() = %b sfd = %d UEventFd::op_mask = %B", UEventFd::fd, socket->iSockDesc, UNotifier::num_connection, UNotifier::min_connection, UServer_Base::isParallelizationChild(), sfd, UEventFd::op_mask); +# endif U_ClientImage_state = U_PLUGIN_HANDLER_ERROR; @@ -986,6 +1001,8 @@ bool UClientImage_Base::genericRead() U_INTERNAL_ASSERT_EQUALS(socket->iSockDesc, UEventFd::fd) + U_gettimeofday // NB: optimization if it is enough a time resolution of one second... + startRequest(); rstart = 0; @@ -1068,8 +1085,6 @@ start: U_INTERNAL_ASSERT_EQUALS(U_ClientImage_pipeline, false) U_INTERNAL_ASSERT_EQUALS(U_ClientImage_data_missing, false) - U_gettimeofday // NB: optimization if it is enough a time resolution of one second... - if (genericRead() == false) { if (U_ClientImage_state == U_PLUGIN_HANDLER_AGAIN && diff --git a/src/ulib/net/server/plugin/usp/fortune.usp b/src/ulib/net/server/plugin/usp/fortune.usp index 165ff624..ad9b6848 100644 --- a/src/ulib/net/server/plugin/usp/fortune.usp +++ b/src/ulib/net/server/plugin/usp/fortune.usp @@ -29,7 +29,7 @@ static void usp_fork_fortune() U_NEW(UOrmStatement, pstmt_fortune, UOrmStatement(*psql_fortune, U_CONSTANT_TO_PARAM("SELECT id, message FROM Fortune"))); - if (UOrmDriver::isPGSQL()) *psql_fortune << "BEGIN ISOLATION LEVEL SERIALIZABLE; COMMIT"; +// if (UOrmDriver::isPGSQL()) *psql_fortune << "BEGIN ISOLATION LEVEL SERIALIZABLE; COMMIT"; U_NEW(Fortune, pfortune, Fortune); @@ -70,6 +70,7 @@ pstmt_fortune->execute(); do { U_NEW(Fortune, item, Fortune(*pfortune)); + pvfortune->push_back(item); } while (pstmt_fortune->nextRow()); diff --git a/src/ulib/net/server/plugin/usp/query.usp b/src/ulib/net/server/plugin/usp/query.usp index 55d43102..fd521d76 100644 --- a/src/ulib/net/server/plugin/usp/query.usp +++ b/src/ulib/net/server/plugin/usp/query.usp @@ -28,7 +28,7 @@ static void usp_fork_query() U_NEW(UOrmStatement, pstmt_query, UOrmStatement(*psql_query, U_CONSTANT_TO_PARAM("SELECT randomNumber FROM World WHERE id = ?"))); - if (UOrmDriver::isPGSQL()) *psql_query << "BEGIN TRANSACTION"; +// if (UOrmDriver::isPGSQL()) *psql_query << "BEGIN TRANSACTION"; U_NEW(World, pworld_query, World); diff --git a/src/ulib/net/server/plugin/usp/update.usp b/src/ulib/net/server/plugin/usp/update.usp index be74f190..c7d1d5ef 100644 --- a/src/ulib/net/server/plugin/usp/update.usp +++ b/src/ulib/net/server/plugin/usp/update.usp @@ -5,14 +5,11 @@ TechEmpower Web Framework Benchmarks diff --git a/src/ulib/net/server/plugin/usp/world.h b/src/ulib/net/server/plugin/usp/world.h index ec55d8d6..581508c9 100644 --- a/src/ulib/net/server/plugin/usp/world.h +++ b/src/ulib/net/server/plugin/usp/world.h @@ -32,6 +32,13 @@ public: U_TRACE_REGISTER_OBJECT(5, World, "%u,%u", _id, _randomNumber) } + World(const World& w) : id(w.id), randomNumber(w.randomNumber) + { + U_TRACE_REGISTER_OBJECT(5, World, "%p", &w) + + U_MEMORY_TEST_COPY(w) + } + ~World() { U_TRACE_UNREGISTER_OBJECT(5, World) @@ -73,6 +80,30 @@ public: stmt->bindResult(U_ORM_TYPE_HANDLER(randomNumber, unsigned int)); } + // SERVICE + + bool operator<(const World& other) const { return cmp_obj(&id, &other.id); } + + static int cmp_obj(const void* a, const void* b) + { + U_TRACE(5, "World::cmp_obj(%p,%p)", a, b) + +# ifdef U_STDCPP_ENABLE + /** + * The comparison function must follow a strict-weak-ordering + * + * 1) For all x, it is not the case that x < x (irreflexivity) + * 2) For all x, y, if x < y then it is not the case that y < x (asymmetry) + * 3) For all x, y, and z, if x < y and y < z then x < z (transitivity) + * 4) For all x, y, and z, if x is incomparable with y, and y is incomparable with z, then x is incomparable with z (transitivity of incomparability) + */ + + return (((const World*)a)->id < (((const World*)b)->id)); +# else + return (*(const World**)a)->id < ((*(const World**)b)->id); +# endif + } + #ifdef DEBUG const char* dump(bool breset) const { diff --git a/src/ulib/net/server/server.cpp b/src/ulib/net/server/server.cpp index 82b9fb14..494dd749 100644 --- a/src/ulib/net/server/server.cpp +++ b/src/ulib/net/server/server.cpp @@ -22,6 +22,10 @@ #include #include +#ifdef U_EVASIVE_SUPPORT +# include +#endif + #ifdef _MSWINDOWS_ # include #else @@ -1000,7 +1004,7 @@ public: uint8_t min_loadavg_remote = 255; uint32_t min_loadavg_remote_ip = 0; - while ((iBytesTransferred = U_SYSCALL(recvfrom, "%d,%p,%u,%u,%p,%p", fd_sock, datagram, sizeof(datagram), MSG_DONTWAIT, (sockaddr*)&(saddr.psaGeneric), &slDummy)) > 0) + while ((iBytesTransferred = U_SYSCALL(recvfrom,"%d,%p,%u,%u,%p,%p",fd_sock,datagram,sizeof(datagram),MSG_DONTWAIT,(sockaddr*)&(saddr.psaGeneric),&slDummy)) > 0) { U_DUMP("Received datagram from (%S:%u) = (%u,%#.*S)", UIPAddress::toString(saddr.psaIP4Addr.sin_addr.s_addr).rep, ntohs(saddr.psaIP4Addr.sin_port), iBytesTransferred, iBytesTransferred, datagram) @@ -1100,6 +1104,371 @@ private: ULock* UServer_Base::lock_ocsp_staple; UThread* UServer_Base::pthread_ocsp; # endif + +/** + * This code provide evasive action in the event of an HTTP DoS or DDoS attack or brute force attack. It is also designed to be a + * detection tool, and can be easily configured to talk to ipchains, firewalls, routers, and etcetera. Detection is performed by + * creating an internal dynamic hash table of IP Addresses and URIs, and denying any single IP address from any of the following: + * + * - Requesting the same page more than a few times per second + * - Making more than 50 concurrent requests per second + * - Making any requests while temporarily blacklisted (on a blocking list) + * + * This method has worked well in both single-server script attacks as well as distributed attacks, but just like other evasive tools, + * is only as useful to the point of bandwidth and processor consumption (e.g. the amount of bandwidth and processor required to + * receive/process/respond to invalid requests), which is why it's a good idea to integrate this with your firewalls and routers. + * + * This code has a built-in cleanup mechanism and scaling capabilities. Because of this, legitimate requests are rarely ever compromised, + * only legitimate attacks. Even a user repeatedly clicking on 'reload' should not be affected unless they do it maliciously, + * + * A web hit request comes in. The following steps take place: + * + * - The IP address of the requestor is looked up on the temporary blacklist. + * - The IP address of the requestor is hashed into a "key". A lookup is performed in the listener's internal hash table to determine if + * the same host has requested more than 50 objects within the past second. + * - The IP address of the requestor and the URI are both hashed into a "key". A lookup is performed in the listener's internal hash table + * to determine if the same host has requested this page more than 3 within the past 1 second. + * + * If any of the above are true, a RESET is sent. This conserves bandwidth and system resources in the event of a DoS attack. Additionally, + * a system command and/or an email notification can also be triggered to block all the originating addresses of a DDoS attack. + * + * Once a single RESET incident occurs, evasive code now blocks the entire IP address for a period of 10 seconds (configurable). If the host + * requests a page within this period, it is forced to wait even longer. Since this is triggered from requesting the same URL multiple times + * per second, this again does not affect legitimate users. + * + * The blacklist can/should be configured to talk to your network's firewalls and/or routers to push the attack out to the front lines, but + * this is not required. This tool is *excellent* at fending off request-based DoS attacks or scripted attacks, and brute force attacks. + * When integrated with firewalls or IP filters, evasive code can stand up to even large attacks. Its features will prevent you from wasting + * bandwidth or having a few thousand CGI scripts running as a result of an attack. + * + * If you do not have an infrastructure capable of fending off any other types of DoS attacks, chances are this tool will only help you to the + * point of your total bandwidth or server capacity for sending RESET's. Without a solid infrastructure and address filtering tool in place, a + * heavy distributed DoS will most likely still take you offline + */ + +# ifdef U_EVASIVE_SUPPORT +class U_NO_EXPORT UEvasive : public UDataStorage { +public: + + uint32_t timestamp, count; + + // COSTRUTTORE + + UEvasive() + { + U_TRACE_REGISTER_OBJECT(0, UEvasive, "", 0) + + (void) memset(×tamp, 0, sizeof(uint32_t) * 2); + } + + ~UEvasive() + { + U_TRACE_UNREGISTER_OBJECT(0, UEvasive) + + if (UServer_Base::db_evasive) + { + UServer_Base::db_evasive->close(); + delete UServer_Base::db_evasive; + } + } + + // define method VIRTUAL of class UDataStorage + + virtual char* toBuffer() + { + U_TRACE_NO_PARAM(0, "UEvasive::toBuffer()") + + U_CHECK_MEMORY + + U_INTERNAL_ASSERT_EQUALS(u_buffer_len, 0) + + U_MEMCPY(u_buffer, ×tamp, u_buffer_len = sizeof(uint32_t) * 2); + + U_INTERNAL_ASSERT_MINOR(u_buffer_len, U_BUFFER_SIZE) + + buffer_len = u_buffer_len; + + U_RETURN(u_buffer); + } + + virtual void fromData(const char* ptr, uint32_t len) + { + U_TRACE(0, "UEvasive::fromData(%.*S,%u)", len, ptr, len) + + U_CHECK_MEMORY + + U_INTERNAL_ASSERT_POINTER(ptr) + U_INTERNAL_ASSERT(len >= sizeof(uint32_t) * 2) + + U_MEMCPY(×tamp, ptr, sizeof(uint32_t) * 2); + } + +#if defined(DEBUG) && defined(U_STDCPP_ENABLE) + const char* dump(bool breset) const { return ""; } +#endif + +private: + U_DISALLOW_COPY_AND_ASSIGN(UEvasive) +}; + +void UServer_Base::initEvasive() +{ + U_TRACE_NO_PARAM(0, "UServer_Base::initEvasive()") + + U_INTERNAL_ASSERT_EQUALS(db_evasive, U_NULLPTR) + + U_NEW(UEvasive, evasive_rec, UEvasive); + U_NEW(URDBObjectHandler, db_evasive, URDBObjectHandler(U_STRING_FROM_CONSTANT("../db/Evasive"), -1, evasive_rec)); + + if (isPreForked()) + { + U_INTERNAL_ASSERT_POINTER(ptr_shared_data) + U_INTERNAL_ASSERT_DIFFERS(ptr_shared_data, MAP_FAILED) + + db_evasive->setShared(U_SRV_LOCK_EVASIVE, U_SRV_SPINLOCK_EVASIVE); + } + + bool result = db_evasive->open(1024 * 1024, false, true); // NB: we don't want truncate (we have only the journal)... + + U_SRV_LOG("%sdb initialization of Evasive %s: size(%u)", (result ? "" : "WARNING: "), (result ? "success" : "failed"), db_evasive->size()); + + if (result) db_evasive->reset(); // Initialize the db to contain no entries + else + { + delete db_evasive; + db_evasive = U_NULLPTR; + } +} + +bool UServer_Base::checkHold(in_addr_t client, const char* client_address, uint32_t client_address_len) +{ + U_TRACE(0, "UServer_Base::checkHold(%u,%.*S,%u)", client, client_address_len, client_address, client_address_len) + + U_INTERNAL_ASSERT_POINTER(db_evasive) + + if ((bwhitelist = (whitelist_IP && UIPAllow::isAllowed(client, *vwhitelist_IP))) == false) // Check whitelist + { + U_gettimeofday // NB: optimization if it is enough a time resolution of one second... + + // First see if the IP itself is on "hold" + + if (db_evasive->getDataStorage(client_address, client_address_len)) + { + U_INTERNAL_DUMP("diff = %u evasive_rec->count = %u", u_now->tv_sec - evasive_rec->timestamp, evasive_rec->count) + + if ((u_now->tv_sec - evasive_rec->timestamp) < blocking_period) + { + // Make it wait longer in blacklist land + + evasive_rec->timestamp = u_now->tv_sec; + + (void) db_evasive->putDataStorage(); + + U_RETURN(true); + } + } + } + + U_RETURN(false); +} + +bool UServer_Base::checkHitStats(const char* key, uint32_t key_len, uint32_t interval, uint32_t count) +{ + U_TRACE(0, "UServer_Base::checkHitStats(%.*S,%u,%u,%u)", key_len, key, key_len, interval, count) + + U_INTERNAL_ASSERT_POINTER(db_evasive) + U_INTERNAL_ASSERT_EQUALS(bwhitelist, false) + + if (db_evasive->getDataStorage(key, key_len) == false) + { + evasive_rec->count = 0; + evasive_rec->timestamp = u_now->tv_sec; + } + else + { + // If site/URI is being hit too much, add to "hold" list + + uint32_t diff = u_now->tv_sec - evasive_rec->timestamp; + + U_INTERNAL_DUMP("diff = %u evasive_rec->count = %u", diff, evasive_rec->count) + + if (diff < interval && + evasive_rec->count >= count) + { + char msg[256]; + uint32_t msg_len = (count == site_count + ? u__snprintf(msg, sizeof(msg), U_CONSTANT_TO_PARAM("it has requested more than %u objects within the past %u seconds"), site_count, site_interval) + : u__snprintf(msg, sizeof(msg), U_CONSTANT_TO_PARAM("it has requested the same page more than %u within the past %u seconds"), page_count, page_interval)); + + evasive_rec->count = 0; + evasive_rec->timestamp = u_now->tv_sec; + + (void) db_evasive->insertDataStorage(U_CLIENT_ADDRESS_TO_PARAM, RDB_REPLACE); + + U_DEBUG("blacklisting address %.*S, possible DoS attack: %.*s", U_CLIENT_ADDRESS_TO_TRACE, msg_len, msg); + + U_SRV_LOG("WARNING: blacklisting address %.*S, possible DoS attack: %.*s", U_CLIENT_ADDRESS_TO_TRACE, msg_len, msg); + + UClientImage_Base::abortive_close(); + + if (emailAddress || + systemCommand) + { + // Perform system functions and/or email notification + + pid_t pid = UServer_Base::startNewChild(); + + if (pid > 0) U_RETURN(true); // parent + + // child + + if (systemCommand) + { + static int fd_stderr; + + if (fd_stderr == 0) fd_stderr = UServices::getDevNull("/tmp/dos_system_command.err"); + + UString cmd(U_CAPACITY); + + cmd.snprintf(U_STRING_TO_PARAM(*systemCommand), U_CLIENT_ADDRESS_TO_TRACE, msg_len, msg); + + UString output = UCommand::outputCommand(cmd, U_NULLPTR, -1, fd_stderr); + + UServer_Base::logCommandMsgError(cmd.data(), true); + + if (UCommand::exit_value) U_WARNING("DOS system command failed: EXIT_VALUE=%d RESPONSE=%V", UCommand::exit_value, output.rep); + } + + if (emailAddress) + { + UString server, rcpt; + uint32_t index = emailAddress->find(':'); + + if (index == U_NOT_FOUND) + { + rcpt = *emailAddress; + server = *UString::str_localhost; + } + else + { + rcpt = emailAddress->substr(index+1); + server = emailAddress->substr(0U, index).copy(); + } + + if (emailClient->_connectServer(server) == false) + { + if (u_buffer_len) + { + U_WARNING("%.*s", u_buffer_len, u_buffer); + + u_buffer_len = 0; + } + } + else + { + UString body(100U); + + body.snprintf(U_CONSTANT_TO_PARAM("blacklisting address %.*S, possible DoS attack: %.*s"), U_CLIENT_ADDRESS_TO_TRACE, msg_len, msg); + + emailClient->setMessageBody(body); + emailClient->setRecipientAddress(rcpt); + emailClient->setMessageSubject(U_STRING_FROM_CONSTANT("possible DoS attack")); + +# ifdef USE_LIBSSL + bool ok = emailClient->sendMessage(true); +# else + bool ok = emailClient->sendMessage(false); +# endif + + if (ok == false) + { + emailClient->setStatus(); + + U_WARNING("DOS email notification to %.*S failed: %.*s", U_STRING_TO_TRACE(*emailAddress), u_buffer_len, u_buffer); + + u_buffer_len = 0; + } + } + } + + if (pid == 0) UServer_Base::endNewChild(); + } + + U_RETURN(true); + } + + if (diff >= interval) evasive_rec->count = 0; // Reset our hit count list as necessary + + evasive_rec->count++; + evasive_rec->timestamp = u_now->tv_sec; + } + + (void) db_evasive->putDataStorage(); + + U_RETURN(false); +} + +bool UServer_Base::checkHitSiteStats() +{ + U_TRACE_NO_PARAM(0, "UServer_Base::checkHitSiteStats()") + + U_INTERNAL_ASSERT_POINTER(db_evasive) + + if (bwhitelist == false) + { + char key[32]; + + U_gettimeofday // NB: optimization if it is enough a time resolution of one second... + + if (checkHitStats(key, u__snprintf(key, sizeof(key), U_CONSTANT_TO_PARAM("%.*s_SITE"), U_CLIENT_ADDRESS_TO_TRACE), site_interval, site_count)) U_RETURN(true); + } + + U_RETURN(false); +} + +bool UServer_Base::checkHitUriStats() +{ + U_TRACE_NO_PARAM(0, "UServer_Base::checkHitUriStats()") + + U_INTERNAL_ASSERT_POINTER(db_evasive) + + if (bwhitelist == false) + { + uint32_t sz = U_http_info.uri_len; + const char* ptr = U_http_info.uri; + +# ifdef U_ALIAS + if (*UClientImage_Base::request_uri) // The interpreted pathname of the original requested document (relative to the document root) + { + sz = UClientImage_Base::request_uri->size(); + ptr = UClientImage_Base::request_uri->data(); + } +# endif + + UString key(UServer_Base::client_address_len + sz); + + key.snprintf(U_CONSTANT_TO_PARAM("%.*s%.*s"), U_CLIENT_ADDRESS_TO_TRACE, sz, ptr); + + if (checkHitStats(U_STRING_TO_PARAM(key), page_interval, page_count)) U_RETURN(true); + } + + U_RETURN(false); +} + +bool UServer_Base::bwhitelist; +uint32_t UServer_Base::page_count; +uint32_t UServer_Base::site_count; +uint32_t UServer_Base::site_interval; +uint32_t UServer_Base::page_interval; +uint32_t UServer_Base::blocking_period; +UString* UServer_Base::emailAddress; +UString* UServer_Base::whitelist_IP; +UString* UServer_Base::systemCommand; +UEvasive* UServer_Base::evasive_rec; +USmtpClient* UServer_Base::emailClient; +UVector* UServer_Base::vwhitelist_IP; +URDBObjectHandler* UServer_Base::db_evasive; +# endif #endif #ifdef U_LINUX @@ -1243,6 +1612,16 @@ UServer_Base::~UServer_Base() if (throttling_mask) delete throttling_mask; #endif +#ifdef U_EVASIVE_SUPPORT + if (evasive_rec) delete evasive_rec; + + if (vwhitelist_IP) + { + delete whitelist_IP; + delete vwhitelist_IP; + } +#endif + #ifdef U_WELCOME_SUPPORT if (msg_welcome) delete msg_welcome; #endif @@ -1528,6 +1907,17 @@ void UServer_Base::loadConfigParam() // 1 - classic, forking after client accept // >1 - pool of serialized processes plus monitoring process // -------------------------------------------------------------------------------------------------------------------------------------- + // This directive are for evasive action in the event of an HTTP DoS or DDoS attack or brute force attack + // -------------------------------------------------------------------------------------------------------------------------------------- + // DOS_PAGE_COUNT this is the threshhold for the number of requests for the same page (or URI) per page interval + // DOS_PAGE_INTERVAL the interval for the page count threshhold; defaults to 1 second intervals + // DOS_SITE_COUNT this is the threshhold for the total number of requests for any object by the same client per site interval + // DOS_SITE_INTERVAL the interval for the site count threshhold; defaults to 1 second intervals + // DOS_BLOCKING_PERIOD the blocking period is the amount of time (in seconds) that a client will be blocked for if they are added to the blocking list (defaults to 10) + // DOS_WHITE_LIST list of comma separated IP addresses of trusted clients can be whitelisted to insure they are never denied (IPADDR[/MASK]) + // DOS_EMAIL_NOTIFY the email address to send a message whenever an IP address becomes blacklisted + // DOS_SYSTEM_COMMAND the system command specified will be executed whenever an IP address becomes blacklisted. Use %v to denote the IP address of the blacklisted IP + // -------------------------------------------------------------------------------------------------------------------------------------- #ifdef USE_LIBSSL U_INTERNAL_DUMP("bssl = %b", bssl) @@ -1659,14 +2049,13 @@ void UServer_Base::loadConfigParam() if (x) { - U_NEW(UString, allow_IP, UString(x)); + U_INTERNAL_ASSERT_EQUALS(allow_IP, U_NULLPTR) + U_NEW(UVector, vallow_IP, UVector); - if (UIPAllow::parseMask(*allow_IP, *vallow_IP) == 0) + if (UIPAllow::parseMask(x, *vallow_IP)) U_NEW(UString, allow_IP, UString(x)); + else { - delete allow_IP; - allow_IP = U_NULLPTR; - delete vallow_IP; vallow_IP = U_NULLPTR; } @@ -1678,14 +2067,13 @@ void UServer_Base::loadConfigParam() if (x) { - U_NEW(UString, allow_IP_prv, UString(x)); + U_INTERNAL_ASSERT_EQUALS(allow_IP_prv, U_NULLPTR) + U_NEW(UVector, vallow_IP_prv, UVector); - if (UIPAllow::parseMask(*allow_IP_prv, *vallow_IP_prv) == 0) + if (UIPAllow::parseMask(x, *vallow_IP_prv)) U_NEW(UString, allow_IP_prv, UString(x)); + else { - delete allow_IP_prv; - allow_IP_prv = U_NULLPTR; - delete vallow_IP_prv; vallow_IP_prv = U_NULLPTR; } @@ -1694,6 +2082,96 @@ void UServer_Base::loadConfigParam() enable_rfc1918_filter = cfg->readBoolean(U_CONSTANT_TO_PARAM("ENABLE_RFC1918_FILTER")); #endif +#ifdef U_EVASIVE_SUPPORT + /** + * This is the threshhold for the number of requests for the same page (or URI) per page interval. + * Once the threshhold for that interval has been exceeded (defaults to 3), the IP address of the client will be added to the blocking list + */ + + page_count = cfg->readLong(U_CONSTANT_TO_PARAM("DOS_PAGE_COUNT"), 3); + + /** + * The interval for the page count threshhold; defaults to 1 second intervals + */ + + page_interval = cfg->readLong(U_CONSTANT_TO_PARAM("DOS_PAGE_INTERVAL"), 1); + + /** + * This is the threshhold for the total number of requests for any object by the same client per site interval. + * Once the threshhold for that interval has been exceeded (defaults to 50), the IP address of the client will be added to the blocking list + */ + + site_count = cfg->readLong(U_CONSTANT_TO_PARAM("DOS_SITE_COUNT"), 50); + + /** + * The interval for the site count threshhold; defaults to 1 second intervals + */ + + site_interval = cfg->readLong(U_CONSTANT_TO_PARAM("DOS_SITE_INTERVAL"), 1); + + /** + * The blocking period is the amount of time (in seconds) that a client will be blocked for if they are added to the blocking list (defaults to 10). + * During this time, all subsequent requests from the client will result in a abortive close and the timer being reset (e.g. another 10 seconds). + * Since the timer is reset for every subsequent request, it is not necessary to have a long blocking period; in the event of a DoS attack, this + * timer will keep getting reset + */ + + blocking_period = cfg->readLong(U_CONSTANT_TO_PARAM("DOS_BLOCKING_PERIOD"), 10); + + /** + * IP addresses of trusted clients can be whitelisted to insure they are never denied. The purpose of whitelisting is to protect software, scripts, local + * searchbots, or other automated tools from being denied for requesting large amounts of data from the server. Whitelisting should *not* be used to add + * customer lists or anything of the sort, as this will open the server to abuse. This module is very difficult to trigger without performing some type of + * malicious attack, and for that reason it is more appropriate to allow the module to decide on its own whether or not an individual customer should be blocked + */ + + x = cfg->at(U_CONSTANT_TO_PARAM("DOS_WHITE_LIST")); + + if (x) + { + U_INTERNAL_ASSERT_EQUALS(whitelist_IP, U_NULLPTR) + + U_NEW(UVector, vwhitelist_IP, UVector); + + if (UIPAllow::parseMask(x, *vwhitelist_IP)) U_NEW(UString, whitelist_IP, UString(x)); + else + { + delete vwhitelist_IP; + vwhitelist_IP = U_NULLPTR; + } + } + + /** + * If this value is set, an email will be sent to the address specified whenever an IP address becomes blacklisted + */ + + x = cfg->at(U_CONSTANT_TO_PARAM("DOS_EMAIL_NOTIFY")); + + if (x) + { + U_INTERNAL_ASSERT_EQUALS(emailClient, U_NULLPTR) + U_INTERNAL_ASSERT_EQUALS(emailAddress, U_NULLPTR) + + U_NEW(UString, emailAddress, UString(x)); + + U_NEW(USmtpClient, emailClient, USmtpClient(UClientImage_Base::bIPv6)); + } + + /** + * If this value is set, the system command specified will be executed whenever an IP address becomes blacklisted. + * This is designed to enable system calls to ip filter or other tools. Use %.*s to denote the IP address of the blacklisted IP + */ + + x = cfg->at(U_CONSTANT_TO_PARAM("DOS_SYSTEM_COMMAND")); + + if (x) + { + U_INTERNAL_ASSERT_EQUALS(systemCommand, U_NULLPTR) + + U_NEW(UString, systemCommand, UString(x)); + } +#endif + // If you want the webserver to run as a process of a defined user, you can do it. // For the change of user to work, it's necessary to execute the server with root privileges. // If it's started by a user that that doesn't have root privileges, this step will be omitted @@ -2546,6 +3024,9 @@ void UServer_Base::init() UTimer::insert(pstat); #endif + + (void) UFile::_mkdir("../db"); + #ifdef U_THROTTLING_SUPPORT if (db_throttling) { @@ -2647,6 +3128,10 @@ void UServer_Base::init() if (throttling_mask) initThrottlingServer(); #endif +#ifdef U_EVASIVE_SUPPORT + initEvasive(); +#endif + if (cfg) cfg->clear(); UInterrupt::syscall_restart = false; @@ -3087,6 +3572,26 @@ try_accept: U_INTERNAL_DUMP("client_address = %.*S", CLIENT_ADDRESS_LEN, CLIENT_ADDRESS) +#ifdef U_EVASIVE_SUPPORT + if (checkHold(CSOCKET->remoteIPAddress().getInAddr(), CLIENT_ADDRESS, CLIENT_ADDRESS_LEN)) + { + CSOCKET->abortive_close(); + +# if defined(ENABLE_THREAD) && !defined(USE_LIBEVENT) && defined(U_SERVER_THREAD_APPROACH_SUPPORT) + if (preforked_num_kids != -1) +# endif + { + U_INTERNAL_ASSERT_DIFFERS(socket_flags & O_NONBLOCK, 0) + +# ifndef USE_LIBEVENT + goto try_next; +# endif + } + + goto next; + } +#endif + #if defined(_MSWINDOWS_) && !defined(USE_LIBEVENT) if (CSOCKET->iSockDesc >= FD_SETSIZE) { diff --git a/src/ulib/utility/http2.cpp b/src/ulib/utility/http2.cpp index 4306fae7..68f08fd5 100644 --- a/src/ulib/utility/http2.cpp +++ b/src/ulib/utility/http2.cpp @@ -3015,7 +3015,7 @@ loop: if (nerror == NO_ERROR) { - U_INTERNAL_ASSERT_MAJOR(pConnection->out_window, 0) + if (pConnection->out_window == 0) goto loop; U_INTERNAL_DUMP("pStreamOld = %u pStream = %u", pStreamOld, pStream) @@ -3416,8 +3416,6 @@ read_request: if (sz == 0) { - // sz = 0 U_http_info.uri_len = 0 U_http2_settings_len = 0 U_ClientImage_close = false - if (U_http2_settings_len) { // NB: not OPTION upgrade... diff --git a/src/ulib/utility/string_ext.cpp b/src/ulib/utility/string_ext.cpp index 172c32a9..53e1ba8c 100644 --- a/src/ulib/utility/string_ext.cpp +++ b/src/ulib/utility/string_ext.cpp @@ -289,7 +289,8 @@ UString UStringExt::dos2unix(const UString& s, bool unix2dos) if (c == '\n') { if (unix2dos) *str++ = '\r'; - *str++ = '\n'; + + *str++ = '\n'; continue; } diff --git a/src/ulib/utility/uhttp.cpp b/src/ulib/utility/uhttp.cpp index 376b51dc..16112843 100644 --- a/src/ulib/utility/uhttp.cpp +++ b/src/ulib/utility/uhttp.cpp @@ -1650,38 +1650,6 @@ __pure bool UHTTP::isValidMethod(const char* ptr) U_RETURN(false); } -__pure bool UHTTP::isValidRequest(const char* ptr, uint32_t sz) -{ - U_TRACE(0, "UHTTP::isValidRequest(%.*S,%u)", 30, ptr, sz) - - U_INTERNAL_ASSERT_MAJOR(sz, 0) - - U_INTERNAL_DUMP("sz = %u UClientImage_Base::size_request = %u", sz, UClientImage_Base::size_request) - - if (u_get_unalignedp32(ptr+sz-4) == U_MULTICHAR_CONSTANT32('\r','\n','\r','\n')) U_RETURN(true); - - U_RETURN(false); -} - -__pure bool UHTTP::isValidRequestExt(const char* ptr, uint32_t sz) -{ - U_TRACE(0, "UHTTP::isValidRequestExt(%.*S,%u)", 30, ptr, sz) - - U_INTERNAL_ASSERT_MAJOR(sz, 0) - - if (sz >= U_CONSTANT_SIZE("GET / HTTP/1.0\r\n\r\n") && - isValidMethod(ptr) && - (isValidRequest(ptr, sz) || - (UClientImage_Base::size_request && - isValidRequest(ptr, UClientImage_Base::size_request)) || - u_findEndHeader1(ptr, sz) != U_NOT_FOUND)) - { - U_RETURN(true); - } - - U_RETURN(false); -} - bool UHTTP::scanfHeaderRequest(const char* ptr, uint32_t size) { U_TRACE(0, "UHTTP::scanfHeaderRequest(%.*S,%u)", size, ptr, size) @@ -1998,6 +1966,7 @@ U_NO_EXPORT bool UHTTP::readHeaderRequest() { U_TRACE_NO_PARAM(0, "UHTTP::readHeaderRequest()") + void* p; uint32_t sz = UClientImage_Base::request->size(); const char* ptr = UClientImage_Base::request->data(); @@ -2033,9 +2002,9 @@ U_NO_EXPORT bool UHTTP::readHeaderRequest() if (u_get_unalignedp32(ptr) == U_MULTICHAR_CONSTANT32('\r','\n','\r','\n')) U_RETURN(true); - sz = u_findEndHeader1(ptr+2, sz-U_http_info.startHeader-2); + p = memmem(ptr+U_CONSTANT_SIZE(U_CRLF), sz-U_http_info.startHeader-U_CONSTANT_SIZE(U_CRLF), U_CONSTANT_TO_PARAM(U_CRLF2)); - if (sz != U_NOT_FOUND) sz += U_http_info.startHeader-2; + if (p) sz = U_http_info.startHeader + (const char*)p - ptr; else { # ifdef USE_LIBSSL @@ -2073,6 +2042,7 @@ bool UHTTP::readHeaderResponse(USocket* sk, UString& buffer) U_INTERNAL_ASSERT_POINTER(sk) + void* p; const char* ptr; uint32_t sz = buffer.size(); @@ -2147,9 +2117,9 @@ loop: sz = buffer.size(); U_INTERNAL_ASSERT_EQUALS(u_get_unalignedp16(ptr), U_MULTICHAR_CONSTANT16('\r','\n')) - sz = u_findEndHeader1(ptr+U_CONSTANT_SIZE(U_CRLF), sz-U_http_info.startHeader-U_CONSTANT_SIZE(U_CRLF)); + p = memmem(ptr+U_CONSTANT_SIZE(U_CRLF), sz-U_http_info.startHeader-U_CONSTANT_SIZE(U_CRLF), U_CONSTANT_TO_PARAM(U_CRLF2)); - if (sz != U_NOT_FOUND) sz += U_http_info.startHeader-U_CONSTANT_SIZE(U_CRLF); + if (p) sz = U_http_info.startHeader + (const char*)p - ptr; else { sz = USocketExt::readWhileNotToken(sk, buffer, U_CONSTANT_TO_PARAM(U_CRLF2), UServer_Base::timeoutMS); @@ -3658,9 +3628,8 @@ bool UHTTP::handlerCache() const char* ptr1 = ptr+UClientImage_Base::size_request; - if (isValidMethod(ptr1) == false || - ( isValidRequest(ptr1, UClientImage_Base::size_request) == false && - u_findEndHeader1(ptr1, UClientImage_Base::size_request) == U_NOT_FOUND)) + if (isValidMethod(ptr1) == false || + u_findEndHeader1(ptr1, UClientImage_Base::size_request) == U_NOT_FOUND) { U_RETURN(false); } @@ -3986,7 +3955,8 @@ int UHTTP::handlerREAD() U_INTERNAL_DUMP("UClientImage_Base::size_request = %u U_http_info.clength = %u", UClientImage_Base::size_request, U_http_info.clength) - /* NB: readBodyRequest() depend on UClientImage_Base::request + /** + * NB: readBodyRequest() depend on UClientImage_Base::request * * if (UClientImage_Base::size_request < UClientImage_Base::request->size()) * { @@ -4314,6 +4284,10 @@ manage: UClientImage_Base::isRequestInFileCache()) // => 3) { file_in_cache: +# ifdef U_EVASIVE_SUPPORT + if (UServer_Base::checkHitUriStats()) U_RETURN(U_PLUGIN_HANDLER_ERROR); +# endif + # if defined(U_HTTP_STRICT_TRANSPORT_SECURITY) || defined(USE_LIBSSL) if (isValidation() == false) U_RETURN(U_PLUGIN_HANDLER_FINISHED); # endif @@ -4435,6 +4409,10 @@ file_exist_and_need_to_be_processed: // NB: if we can't service the content of f UClientImage_Base::setRequestNeedProcessing(); } +# ifdef U_EVASIVE_SUPPORT + if (UServer_Base::checkHitUriStats()) U_RETURN(U_PLUGIN_HANDLER_ERROR); +# endif + # if defined(U_HTTP_STRICT_TRANSPORT_SECURITY) || defined(USE_LIBSSL) if (isValidation() == false) U_RETURN(U_PLUGIN_HANDLER_FINISHED); # endif @@ -4442,6 +4420,15 @@ file_exist_and_need_to_be_processed: // NB: if we can't service the content of f goto end; } +#ifdef U_EVASIVE_SUPPORT + if (UClientImage_Base::isRequestNotFound() == false && // => 4) + UClientImage_Base::isRequestAlreadyProcessed() == false && // => 5) + UServer_Base::checkHitUriStats()) + { + U_RETURN(U_PLUGIN_HANDLER_ERROR); + } +#endif + #if defined(U_HTTP_STRICT_TRANSPORT_SECURITY) || defined(USE_LIBSSL) if ( UClientImage_Base::isRequestNotFound() == false && // => 4) (UClientImage_Base::isRequestAlreadyProcessed() || // => 5) diff --git a/tests/examples/benchmark/FrameworkBenchmarks/ULib/setup_mysql.sh b/tests/examples/benchmark/FrameworkBenchmarks/ULib/setup_mysql.sh index 01339c7d..e2173365 100755 --- a/tests/examples/benchmark/FrameworkBenchmarks/ULib/setup_mysql.sh +++ b/tests/examples/benchmark/FrameworkBenchmarks/ULib/setup_mysql.sh @@ -4,7 +4,7 @@ fw_depends mysql ulib # Travis is broken if [ "$TRAVIS" != "true" ]; then -MAX_THREADS=$(( 3 * $CPU_COUNT / 2 )) +MAX_THREADS=$CPU_COUNT else MAX_THREADS=$(( 2 * $CPU_COUNT )) fi diff --git a/tests/examples/benchmark/FrameworkBenchmarks/ULib/src/fortune.usp b/tests/examples/benchmark/FrameworkBenchmarks/ULib/src/fortune.usp index 165ff624..ad9b6848 100644 --- a/tests/examples/benchmark/FrameworkBenchmarks/ULib/src/fortune.usp +++ b/tests/examples/benchmark/FrameworkBenchmarks/ULib/src/fortune.usp @@ -29,7 +29,7 @@ static void usp_fork_fortune() U_NEW(UOrmStatement, pstmt_fortune, UOrmStatement(*psql_fortune, U_CONSTANT_TO_PARAM("SELECT id, message FROM Fortune"))); - if (UOrmDriver::isPGSQL()) *psql_fortune << "BEGIN ISOLATION LEVEL SERIALIZABLE; COMMIT"; +// if (UOrmDriver::isPGSQL()) *psql_fortune << "BEGIN ISOLATION LEVEL SERIALIZABLE; COMMIT"; U_NEW(Fortune, pfortune, Fortune); @@ -70,6 +70,7 @@ pstmt_fortune->execute(); do { U_NEW(Fortune, item, Fortune(*pfortune)); + pvfortune->push_back(item); } while (pstmt_fortune->nextRow()); diff --git a/tests/examples/benchmark/FrameworkBenchmarks/ULib/src/query.usp b/tests/examples/benchmark/FrameworkBenchmarks/ULib/src/query.usp index 55d43102..fd521d76 100644 --- a/tests/examples/benchmark/FrameworkBenchmarks/ULib/src/query.usp +++ b/tests/examples/benchmark/FrameworkBenchmarks/ULib/src/query.usp @@ -28,7 +28,7 @@ static void usp_fork_query() U_NEW(UOrmStatement, pstmt_query, UOrmStatement(*psql_query, U_CONSTANT_TO_PARAM("SELECT randomNumber FROM World WHERE id = ?"))); - if (UOrmDriver::isPGSQL()) *psql_query << "BEGIN TRANSACTION"; +// if (UOrmDriver::isPGSQL()) *psql_query << "BEGIN TRANSACTION"; U_NEW(World, pworld_query, World); diff --git a/tests/examples/benchmark/FrameworkBenchmarks/ULib/src/update.usp b/tests/examples/benchmark/FrameworkBenchmarks/ULib/src/update.usp index be74f190..c7d1d5ef 100644 --- a/tests/examples/benchmark/FrameworkBenchmarks/ULib/src/update.usp +++ b/tests/examples/benchmark/FrameworkBenchmarks/ULib/src/update.usp @@ -5,14 +5,11 @@ TechEmpower Web Framework Benchmarks diff --git a/tests/examples/benchmark/FrameworkBenchmarks/ULib/src/world.h b/tests/examples/benchmark/FrameworkBenchmarks/ULib/src/world.h index d7a746dc..812782f6 100644 --- a/tests/examples/benchmark/FrameworkBenchmarks/ULib/src/world.h +++ b/tests/examples/benchmark/FrameworkBenchmarks/ULib/src/world.h @@ -32,6 +32,13 @@ public: U_TRACE_REGISTER_OBJECT(5, World, "%u,%u", _id, _randomNumber) } + World(const World& w) : id(w.id), randomNumber(w.randomNumber) + { + U_TRACE_REGISTER_OBJECT(5, World, "%p", &w) + + U_MEMORY_TEST_COPY(w) + } + ~World() { U_TRACE_UNREGISTER_OBJECT(5, World) @@ -73,6 +80,30 @@ public: stmt->bindResult(U_ORM_TYPE_HANDLER(randomNumber, unsigned int)); } + // SERVICE + + bool operator<(const World& other) const { return cmp_obj(&id, &other.id); } + + static int cmp_obj(const void* a, const void* b) + { + U_TRACE(5, "World::cmp_obj(%p,%p)", a, b) + +# ifdef U_STDCPP_ENABLE + /** + * The comparison function must follow a strict-weak-ordering + * + * 1) For all x, it is not the case that x < x (irreflexivity) + * 2) For all x, y, if x < y then it is not the case that y < x (asymmetry) + * 3) For all x, y, and z, if x < y and y < z then x < z (transitivity) + * 4) For all x, y, and z, if x is incomparable with y, and y is incomparable with z, then x is incomparable with z (transitivity of incomparability) + */ + + return (((const World*)a)->id < (((const World*)b)->id)); +# else + return (*(const World**)a)->id < ((*(const World**)b)->id); +# endif + } + #ifdef DEBUG const char* dump(bool breset) const { diff --git a/tests/examples/client_server.test b/tests/examples/client_server.test index d186716e..0c6c26eb 100755 --- a/tests/examples/client_server.test +++ b/tests/examples/client_server.test @@ -18,8 +18,8 @@ cat <inp/server.cf userver { PORT 10001 WELCOME_MSG "generic server ready." - ALLOWED_IP localhost -#ALLOWED_IP localhost,10.30.0.0/16 + ALLOWED_IP 127.0.0.1 +#ALLOWED_IP 127.0.0.1,10.30.0.0/16 LOG_FILE server.log LOG_FILE_SZ 1M PLUGIN echo diff --git a/tests/examples/inp/server.cf b/tests/examples/inp/server.cf index 74f6ef57..d1759234 100644 --- a/tests/examples/inp/server.cf +++ b/tests/examples/inp/server.cf @@ -1,8 +1,8 @@ userver { PORT 10001 WELCOME_MSG "generic server ready." - ALLOWED_IP localhost -#ALLOWED_IP localhost,10.30.0.0/16 + ALLOWED_IP 127.0.0.1 +#ALLOWED_IP 127.0.0.1,10.30.0.0/16 LOG_FILE server.log LOG_FILE_SZ 1M PLUGIN echo diff --git a/tests/examples/web_server.test b/tests/examples/web_server.test index 3692c646..9df05959 100755 --- a/tests/examples/web_server.test +++ b/tests/examples/web_server.test @@ -100,6 +100,8 @@ done upload_test $2:8080 kill_server userver_tcp +$SLEEP +pkill userver_tcp 2>/dev/null } # function : creat_config @@ -117,6 +119,7 @@ userver { RUN_AS_USER nobody #MIN_SIZE_FOR_SENDFILE 2k REQ_TIMEOUT 30 + DOS_WHITE_LIST 127.0.0.1,10.30.0.0/16 LOG_FILE webserver$1.log LOG_FILE_SZ 1M LOG_MSG_SIZE -1 diff --git a/tests/examples/web_server_multiclient.test b/tests/examples/web_server_multiclient.test index 8b181111..e73a95e3 100755 --- a/tests/examples/web_server_multiclient.test +++ b/tests/examples/web_server_multiclient.test @@ -30,6 +30,7 @@ cat <inp/webserver.cfg userver { PORT 8080 RUN_AS_USER apache + DOS_WHITE_LIST 127.0.0.1,10.30.0.0/16 LOG_FILE web_server_multiclient.log LOG_FILE_SZ 1M LOG_MSG_SIZE -1 diff --git a/tests/examples/web_server_ssl.test b/tests/examples/web_server_ssl.test index 34bc95c4..26ca00f6 100755 --- a/tests/examples/web_server_ssl.test +++ b/tests/examples/web_server_ssl.test @@ -112,6 +112,7 @@ userver { RUN_AS_USER nobody REQ_TIMEOUT 30 #MIN_SIZE_FOR_SENDFILE 2k + DOS_WHITE_LIST 127.0.0.1,10.30.0.0/16 LOG_FILE webserver_ssl$1.log LOG_FILE_SZ 1M LOG_MSG_SIZE -1 diff --git a/tests/ulib/README b/tests/ulib/README index 44910013..152167cc 100644 --- a/tests/ulib/README +++ b/tests/ulib/README @@ -1,14 +1,17 @@ See http://www.debian.org/ for information about Debian GNU/Linux. Four Debian releases are available on the main site: -Debian 7.11, or wheezy. Access this release through dists/oldstable +Debian 7.11, or wheezy. Access this release through dists/oldoldstable Debian 7.11 was released Saturday, 4th June 2016. -Debian 8.8, or jessie. Access this release through dists/stable +Debian 8.8, or jessie. Access this release through dists/oldstable Debian 8.8 was released Saturday, 6th May 2017. -Testing, or stretch. Access this release through dists/testing. The -current tested development snapshot is named stretch. Packages which +Debian 9.0, or stretch. Access this release through dists/stable +Debian 9.0 was released Saturday, 17th June 2017. + +Testing, or buster. Access this release through dists/testing. The +current tested development snapshot is named buster. Packages which have been tested in unstable and passed automated tests propagate to this release. diff --git a/tests/ulib/inp/rdb_server.cf b/tests/ulib/inp/rdb_server.cf index e2a83386..c7e3a1c2 100644 --- a/tests/ulib/inp/rdb_server.cf +++ b/tests/ulib/inp/rdb_server.cf @@ -2,6 +2,10 @@ SERVER { PORT 8080 + DOS_WHITE_LIST 127.0.0.1,10.30.0.0/16 + DOS_EMAIL_NOTIFY mail.unirel.com:stefano.casazza2@unirel.com + DOS_SYSTEM_COMMAND "sh -c 'echo %.*s: %.*s >> /tmp/dos_blacklist.txt'" + LOG_FILE rdb_server.log LOG_FILE_SZ 1M diff --git a/tests/ulib/ok/curl.ok b/tests/ulib/ok/curl.ok index 79b82fcc..85b204b0 100644 --- a/tests/ulib/ok/curl.ok +++ b/tests/ulib/ok/curl.ok @@ -43,14 +43,17 @@ URL: ftp://ftp.at.debian.org/debian/README See http://www.debian.org/ for information about Debian GNU/Linux. Four Debian releases are available on the main site: -Debian 7.9, or wheezy. Access this release through dists/oldstable -Debian 7.9 was released Saturday, 5th September 2015. +Debian 7.11, or wheezy. Access this release through dists/oldoldstable +Debian 7.11 was released Saturday, 4th June 2016. -Debian 8.3, or jessie. Access this release through dists/stable -Debian 8.3 was released Saturday, 23rd January 2016. +Debian 8.8, or jessie. Access this release through dists/oldstable +Debian 8.8 was released Saturday, 6th May 2017. -Testing, or stretch. Access this release through dists/testing. The -current tested development snapshot is named stretch. Packages which +Debian 9.0, or stretch. Access this release through dists/stable +Debian 9.0 was released Saturday, 17th June 2017. + +Testing, or buster. Access this release through dists/testing. The +current tested development snapshot is named buster. Packages which have been tested in unstable and passed automated tests propagate to this release. @@ -105,7 +108,7 @@ the webmaster.
www.unirel.com
- Wed Mar 2 18:45:49 2016
+ Mon Jun 19 14:01:54 2017
Apache/2.0.49 (Linux/SuSE)
diff --git a/tests/ulib/ok/ftp.ok b/tests/ulib/ok/ftp.ok index 23cd85b9..152167cc 100644 --- a/tests/ulib/ok/ftp.ok +++ b/tests/ulib/ok/ftp.ok @@ -1,14 +1,17 @@ See http://www.debian.org/ for information about Debian GNU/Linux. Four Debian releases are available on the main site: -Debian 7.9, or wheezy. Access this release through dists/oldstable -Debian 7.9 was released Saturday, 5th September 2015. +Debian 7.11, or wheezy. Access this release through dists/oldoldstable +Debian 7.11 was released Saturday, 4th June 2016. -Debian 8.3, or jessie. Access this release through dists/stable -Debian 8.3 was released Saturday, 23rd January 2016. +Debian 8.8, or jessie. Access this release through dists/oldstable +Debian 8.8 was released Saturday, 6th May 2017. -Testing, or stretch. Access this release through dists/testing. The -current tested development snapshot is named stretch. Packages which +Debian 9.0, or stretch. Access this release through dists/stable +Debian 9.0 was released Saturday, 17th June 2017. + +Testing, or buster. Access this release through dists/testing. The +current tested development snapshot is named buster. Packages which have been tested in unstable and passed automated tests propagate to this release. diff --git a/tests/ulib/test_rdb_client.cpp b/tests/ulib/test_rdb_client.cpp index 805605c6..0890cfdd 100644 --- a/tests/ulib/test_rdb_client.cpp +++ b/tests/ulib/test_rdb_client.cpp @@ -61,7 +61,7 @@ U_EXPORT main(int argc, char* argv[], char* env[]) int result; UString host(argv[1]); - URDBClient x(0); + URDBClient x(U_NULLPTR); if (x.setHostPort(host, 8080) && x.connect()) { diff --git a/tests/ulib/test_server.cpp b/tests/ulib/test_server.cpp index e623f4a5..7b17e014 100644 --- a/tests/ulib/test_server.cpp +++ b/tests/ulib/test_server.cpp @@ -14,7 +14,7 @@ U_EXPORT main (int argc, char* argv[], char* env[]) U_TRACE(5,"main(%d)",argc) UFileConfig fcg; - UServerExample server(0); + UServerExample server(U_NULLPTR); UString plugin_dir(argv[1]), plugin_list(argv[2]); if (argv[3])