From d606b1d18ce36974fd738d83449c1e3ae0e60f4a Mon Sep 17 00:00:00 2001 From: Robert Paprocki Date: Wed, 7 Sep 2016 09:05:38 -0700 Subject: [PATCH] Implement translation pause action Leverage ngx.sleep() to mimic ModSecurity's pause action. We label this as nondisruptive instead of disruptive, as this will not block the worker or any other request. --- lib/resty/waf/actions.lua | 5 +++ t/translate/15_translate_actions.t | 52 +++++++++++++++++++++++++ t/unit/actions/nondisruptive/05_sleep.t | 42 ++++++++++++++++++++ tools/Modsec2LRW.pm | 8 ++++ 4 files changed, 107 insertions(+) create mode 100644 t/unit/actions/nondisruptive/05_sleep.t diff --git a/lib/resty/waf/actions.lua b/lib/resty/waf/actions.lua index f4498149..c95bbcb1 100644 --- a/lib/resty/waf/actions.lua +++ b/lib/resty/waf/actions.lua @@ -66,6 +66,11 @@ _M.nondisruptive_lookup = { storage.set_var(waf, ctx, data, value) end, + sleep = function(waf, time) + logger.log(waf, "Sleeping for " .. time) + + ngx.sleep(time) + end, } return _M diff --git a/t/translate/15_translate_actions.t b/t/translate/15_translate_actions.t index 253812f4..2f6ec614 100644 --- a/t/translate/15_translate_actions.t +++ b/t/translate/15_translate_actions.t @@ -868,6 +868,58 @@ warning_like 'warn when setvar sets not value, but does not prepend !' ; +$translation = {}; +translate_actions( + { + actions => [ + { + action => 'pause', + value => 5000, + } + ] + }, + $translation, + undef +); +is_deeply( + $translation, + { + actions => { + nondisrupt => [ { + action => 'sleep', + data => 5, + } ] + } + }, + 'translate pause' +); + +$translation = {}; +translate_actions( + { + actions => [ + { + action => 'pause', + value => 125, + } + ] + }, + $translation, + undef +); +is_deeply( + $translation, + { + actions => { + nondisrupt => [ { + action => 'sleep', + data => 0.125, + } ] + } + }, + 'translate pause with decimal value' +); + $translation = {}; translate_actions( { diff --git a/t/unit/actions/nondisruptive/05_sleep.t b/t/unit/actions/nondisruptive/05_sleep.t new file mode 100644 index 00000000..ed753de3 --- /dev/null +++ b/t/unit/actions/nondisruptive/05_sleep.t @@ -0,0 +1,42 @@ +use Test::Nginx::Socket::Lua; + +repeat_each(3); +plan tests => repeat_each() * 4 * blocks(); + +no_shuffle(); +run_tests(); + +__DATA__ + +=== TEST 1: sleep calls ngx.sleep +--- http_config +init_by_lua_block{ + if (os.getenv("LRW_COVERAGE")) then + runner = require "luacov.runner" + runner.tick = true + runner.init({savestepsize = 1}) + jit.off() + end +} +--- config + location /t { + content_by_lua ' + local actions = require "resty.waf.actions" + + ngx.sleep = function(time) + ngx.say("Slept for " .. time .. " seconds") + end + + actions.nondisruptive_lookup["sleep"]({ _debug = true, _debug_log_level = ngx.INFO }, 5) + '; + } +--- request +GET /t +--- error_code: 200 +--- response_body +Slept for 5 seconds +--- error_log +Sleeping for 5 +--- no_error_log +[error] + diff --git a/tools/Modsec2LRW.pm b/tools/Modsec2LRW.pm index 06554268..797ef05f 100644 --- a/tools/Modsec2LRW.pm +++ b/tools/Modsec2LRW.pm @@ -821,6 +821,14 @@ sub translate_actions { action => 'setvar', data => $setvar }; + } elsif ($key eq 'pause') { + my $time = $value / 1000; # pause:n is given in ms, ngx.sleep takes its arg as seconds + + push @{$translation->{actions}->{nondisrupt}}, + { + action => 'sleep', + data => $time, + }; } elsif ($key eq 't') { next if $value eq 'none';