Merge 240a5a12c1
into 314a2f62ec
commit
8d4aaef8f3
79
README.md
79
README.md
|
@ -1,3 +1,34 @@
|
|||
水平太烂,只能在原基础上改改。
|
||||
|
||||
1.原cc功能有点弱,改进后可以提高对攻击和普通访问的限制
|
||||
|
||||
默认同ip触发规则攻击超过10次/5秒,限制该ip访问nginx服务器1800秒。
|
||||
|
||||
同1 ip访问同1地址30次/60秒,限制访问该地址30秒。
|
||||
|
||||
2.日志主要是用于syslog服务器能力。
|
||||
|
||||
1.--保存日志到syslog,可以用nginx设置的日志服务器保存日志。
|
||||
|
||||
logtoserver = "on"
|
||||
|
||||
2.--通过加载socket.lua同时使用其他日志服务器,默认关闭。(这个有点粗糙,有需要的自己改)
|
||||
|
||||
loghack="off"
|
||||
|
||||
3.修改whiteurl,可以针对域名设置白名单。
|
||||
|
||||
--whiteurl start
|
||||
|
||||
site:^www.baidu.com/whiteurl/
|
||||
|
||||
--end
|
||||
|
||||
|
||||
------------------分割线-------------------------------------------------
|
||||
|
||||
---------------lovshell记录----------------------------------------------
|
||||
|
||||
##ngx_lua_waf
|
||||
|
||||
ngx_lua_waf是我刚入职趣游时候开发的一个基于ngx_lua的web应用防火墙。
|
||||
|
@ -136,3 +167,51 @@ nginx安装路径假设为:/usr/local/nginx/conf/
|
|||
</table>
|
||||
|
||||
感谢ngx_lua模块的开发者[@agentzh](https://github.com/agentzh/),春哥是我所接触过开源精神最好的人
|
||||
|
||||
|
||||
syntax: captures, err = ngx.re.match(subject, regex, options?, ctx?, res_table?)
|
||||
syntax: from, to, err = ngx.re.find(subject, regex, options?, ctx?, nth?)
|
||||
|
||||
Specify options to control how the match operation will be performed. The following option characters are supported:
|
||||
|
||||
a anchored mode (only match from the beginning)
|
||||
|
||||
d enable the DFA mode (or the longest token match semantics).
|
||||
this requires PCRE 6.0+ or else a Lua exception will be thrown.
|
||||
first introduced in ngx_lua v0.3.1rc30.
|
||||
|
||||
D enable duplicate named pattern support. This allows named
|
||||
subpattern names to be repeated, returning the captures in
|
||||
an array-like Lua table. for example,
|
||||
local m = ngx.re.match("hello, world",
|
||||
"(?<named>\w+), (?<named>\w+)",
|
||||
"D")
|
||||
-- m["named"] == {"hello", "world"}
|
||||
this option was first introduced in the v0.7.14 release.
|
||||
this option requires at least PCRE 8.12.
|
||||
|
||||
i case insensitive mode (similar to Perl's /i modifier)
|
||||
|
||||
j enable PCRE JIT compilation, this requires PCRE 8.21+ which
|
||||
must be built with the --enable-jit option. for optimum performance,
|
||||
this option should always be used together with the 'o' option.
|
||||
first introduced in ngx_lua v0.3.1rc30.
|
||||
|
||||
J enable the PCRE Javascript compatible mode. this option was
|
||||
first introduced in the v0.7.14 release. this option requires
|
||||
at least PCRE 8.12.
|
||||
|
||||
m multi-line mode (similar to Perl's /m modifier)
|
||||
|
||||
o compile-once mode (similar to Perl's /o modifier),
|
||||
to enable the worker-process-level compiled-regex cache
|
||||
|
||||
s single-line mode (similar to Perl's /s modifier)
|
||||
|
||||
u UTF-8 mode. this requires PCRE to be built with
|
||||
the --enable-utf8 option or else a Lua exception will be thrown.
|
||||
|
||||
U similar to "u" but disables PCRE's UTF-8 validity check on
|
||||
the subject string. first introduced in ngx_lua v0.8.1.
|
||||
|
||||
x extended mode (similar to Perl's /x modifier)
|
||||
|
|
24
config.lua
24
config.lua
|
@ -1,23 +1,35 @@
|
|||
RulePath = "/usr/local/nginx/conf/waf/wafconf/"
|
||||
RulePath = "/etc/nginx/waf/wafconf/"
|
||||
attacklog = "on"
|
||||
logdir = "/usr/local/nginx/logs/hack/"
|
||||
--保存日志到文件
|
||||
logtofile = "off"
|
||||
logdir = "/var/log/nginx/"
|
||||
--保存日志到syslog,采用nginx设置
|
||||
logtoserver = "on"
|
||||
--通过syslog日志方式提交hack_ip记录到日志服务器
|
||||
loghack="off"
|
||||
------------
|
||||
UrlDeny="on"
|
||||
Redirect="on"
|
||||
CookieMatch="on"
|
||||
postMatch="on"
|
||||
whiteModule="on"
|
||||
black_fileExt={"php","jsp"}
|
||||
ipWhitelist={"127.0.0.1"}
|
||||
ipWhitelist={"127.0.0.1","192.168.2.1"}
|
||||
ipBlocklist={"1.0.0.1"}
|
||||
CCDeny="off"
|
||||
CCrate="100/60"
|
||||
--违规ip登记,是否限制访问。
|
||||
--hackrate超过10次/5秒,限制访问1800秒。
|
||||
hackipdeny="on"
|
||||
hackrate="10/60/1800"
|
||||
--cc攻击防范
|
||||
CCDeny="on"
|
||||
CCrate="30/60/30"
|
||||
html=[[
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>网站防火墙</title>
|
||||
<style>
|
||||
p {
|
||||
line-height:20px;
|
||||
line-height:20px;
|
||||
}
|
||||
ul{ list-style-type:none;}
|
||||
li{ list-style-type:none;}
|
||||
|
|
143
init.lua
143
init.lua
|
@ -1,19 +1,52 @@
|
|||
require 'config'
|
||||
local match = string.match
|
||||
local ngxmatch=ngx.re.match
|
||||
--ngx_lua如果是0.9.2以上版本,建议正则过滤函数改为ngx.re.find,匹配效率会提高三倍左右。
|
||||
--因nginx和lua一起的关系,正则表达式使用\d\w\s会出问题,
|
||||
--local ngxmatch=ngx.re.match
|
||||
local ngxmatch=ngx.re.find
|
||||
local unescape=ngx.unescape_uri
|
||||
local get_headers = ngx.req.get_headers
|
||||
local optionIsOn = function (options) return options == "on" and true or false end
|
||||
loghack=optionIsOn(loghack)
|
||||
--载入socket.lua用于发送log到独立syslog服务器。
|
||||
local logger = require "socket"
|
||||
if loghack then
|
||||
|
||||
|
||||
if not logger.initted() then
|
||||
local ok, err = logger.init{
|
||||
--host = '192.168.0.1',
|
||||
host = 'logserver.local',
|
||||
port = 514,
|
||||
sock_type = "udp", --udp协议
|
||||
flush_limit = 1, --立即发送
|
||||
--drop_limit = 5678,
|
||||
pool_size = 100,--连接池大小
|
||||
}
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR, "failed to initialize the logger: ",
|
||||
err)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
logpath = logdir
|
||||
rulepath = RulePath
|
||||
logtofile = optionIsOn(logtofile)
|
||||
logtoserver = optionIsOn(logtoserver)
|
||||
UrlDeny = optionIsOn(UrlDeny)
|
||||
PostCheck = optionIsOn(postMatch)
|
||||
CookieCheck = optionIsOn(cookieMatch)
|
||||
WhiteCheck = optionIsOn(whiteModule)
|
||||
PathInfoFix = optionIsOn(PathInfoFix)
|
||||
attacklog = optionIsOn(attacklog)
|
||||
hackipdeny = optionIsOn(hackipdeny)
|
||||
CCDeny = optionIsOn(CCDeny)
|
||||
Redirect=optionIsOn(Redirect)
|
||||
local file = io.open('config')
|
||||
|
||||
function getClientIp()
|
||||
IP = ngx.var.remote_addr
|
||||
if IP == nil then
|
||||
|
@ -28,19 +61,38 @@ function write(logfile,msg)
|
|||
fd:flush()
|
||||
fd:close()
|
||||
end
|
||||
|
||||
function swrite(msg)
|
||||
--保存警告等级要高于nginx error_log的默认等级。
|
||||
ngx.log(ngx.CRIT,msg)
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
function log(method,url,data,ruletag)
|
||||
if attacklog then
|
||||
local realIp = getClientIp()
|
||||
local ua = ngx.var.http_user_agent
|
||||
local servername=ngx.var.server_name
|
||||
local time=ngx.localtime()
|
||||
if ua then
|
||||
line = realIp.." ["..time.."] \""..method.." "..servername..url.."\" \""..data.."\" \""..ua.."\" \""..ruletag.."\"\n"
|
||||
else
|
||||
line = realIp.." ["..time.."] \""..method.." "..servername..url.."\" \""..data.."\" - \""..ruletag.."\"\n"
|
||||
if ua == nil then
|
||||
ua="null"
|
||||
end
|
||||
local servername=ngx.var.host
|
||||
local time=ngx.localtime()
|
||||
if logtofile then
|
||||
local filename = logpath..'/'..servername.."_"..ngx.today().."_sec.log"
|
||||
line=realIp.." ["..time.."]".."\""..method.." "..servername..url.."\""..data.."\""..ua.."\""..ruletag.."\"".."\n"
|
||||
write(filename,line)
|
||||
end
|
||||
if logtoserver then
|
||||
line=realIp.."\""..method.." "..servername..url.."\""..data.."\""..ua.."\""..ruletag.."\""
|
||||
--line="lua_waf:"..line
|
||||
swrite(line)
|
||||
end
|
||||
--发送ip到独立syslog服务器。
|
||||
if loghack then local bytes, err = logger.log(getClientIp()) end
|
||||
--只要log记录,说明被攻击,利用denyhackip将ip记录。
|
||||
if hackipdeny then denyhackip(0) end
|
||||
end
|
||||
end
|
||||
------------------------------------规则读取函数-------------------------------------------------------------------
|
||||
|
@ -78,21 +130,35 @@ function whiteurl()
|
|||
if WhiteCheck then
|
||||
if wturlrules ~=nil then
|
||||
for _,rule in pairs(wturlrules) do
|
||||
if ngxmatch(ngx.var.uri,rule,"isjo") then
|
||||
--针对site:开始的进行域名匹配。增加白名单用处。
|
||||
local sitemod,_=string.find(rule,"site:")
|
||||
if sitemod==1 then
|
||||
rule=string.gsub(rule,"site:","",1)
|
||||
--调试whiteurl
|
||||
--if ngx.var.host=='domino.cqhrss.gov.cn' then
|
||||
-- log('debug',ngx.var.uri,"",rule)
|
||||
--end
|
||||
if ngxmatch(ngx.var.host..ngx.var.uri,rule,"isjo") then
|
||||
return true
|
||||
end
|
||||
end
|
||||
else
|
||||
if ngxmatch(ngx.var.uri,rule,"isjo") then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function fileExtCheck(ext)
|
||||
local items = Set(black_fileExt)
|
||||
ext=string.lower(ext)
|
||||
if ext then
|
||||
for rule in pairs(items) do
|
||||
if ngx.re.match(ext,rule,"isjo") then
|
||||
log('POST',ngx.var.request_uri,"-","file attack with ext "..ext)
|
||||
for rule,_ in pairs(items) do
|
||||
if ngxmatch(ext,rule,"isjo") then
|
||||
log('POST',ngx.var.request_uri,"-","file attack with ext "..ext)
|
||||
say_html()
|
||||
end
|
||||
end
|
||||
|
@ -184,17 +250,25 @@ end
|
|||
function denycc()
|
||||
if CCDeny then
|
||||
local uri=ngx.var.uri
|
||||
CCcount=tonumber(string.match(CCrate,'(.*)/'))
|
||||
CCseconds=tonumber(string.match(CCrate,'/(.*)'))
|
||||
local m, err = ngx.re.match(CCrate,'([0-9]+)/([0-9]+)/([0-9]+)')
|
||||
local CCcount=tonumber(m[1]) --计数器上限
|
||||
local CCseconds=tonumber(m[2]) --计时器
|
||||
local CClimits=tonumber(m[3]) --阻止访问时间
|
||||
local token = getClientIp()..uri
|
||||
local limit = ngx.shared.limit
|
||||
local req,_=limit:get(token)
|
||||
local req,_=limit:get(token) --计数器当前值
|
||||
|
||||
if req then
|
||||
if req > CCcount then
|
||||
ngx.exit(503)
|
||||
ngx.exit(404)
|
||||
return true
|
||||
else
|
||||
limit:incr(token,1)
|
||||
if req == CCcount then limit:set(token,CCcount+1,CClimits) end
|
||||
|
||||
limit:incr(token,1)
|
||||
--调试在syslog日志中查看
|
||||
--swrite('计数器:'..token..'当前计数器'..req..'阻止访问时间:'..CClimits)
|
||||
|
||||
end
|
||||
else
|
||||
limit:set(token,1,CCseconds)
|
||||
|
@ -203,6 +277,41 @@ function denycc()
|
|||
return false
|
||||
end
|
||||
|
||||
--chk为1表示检测值,不增加,不创建,返回检测结果。
|
||||
function denyhackip(chk)
|
||||
if hackipdeny then
|
||||
|
||||
local m, err = ngx.re.match(hackrate,'([0-9]+)/([0-9]+)/([0-9]+)')
|
||||
local hicount=tonumber(m[1]) --计数器上限
|
||||
local hiseconds=tonumber(m[2]) --计时器
|
||||
local hilimits=tonumber(m[3]) --阻止访问时间
|
||||
local token = "hackip"..getClientIp()
|
||||
local limit = ngx.shared.limit
|
||||
local req,_=limit:get(token) --计数器当前值
|
||||
if req then
|
||||
if req > hicount then
|
||||
ngx.exit(404)
|
||||
return true
|
||||
else
|
||||
|
||||
if req == hicount then
|
||||
limit:set(token,hicount+1,hilimits)
|
||||
swrite("ip:"..getClientIp().."因攻击被暂停访问"..hilimits.."秒。")
|
||||
end
|
||||
if chk ~=1 then limit:incr(token,1) end
|
||||
--调试在syslog日志中查看
|
||||
--swrite("计数器:"..token.."检测状态:"..chk.."当前计数器"..req.."阻止访问时间:"..hilimits)
|
||||
|
||||
|
||||
end
|
||||
else
|
||||
if chk ~=1 then limit:set(token,1,hiseconds) end
|
||||
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function get_boundary()
|
||||
local header = get_headers()["content-type"]
|
||||
if not header then
|
||||
|
|
|
@ -0,0 +1,558 @@
|
|||
-- Copyright (C) 2013-2014 Jiale Zhi (calio), CloudFlare Inc.
|
||||
--require "luacov"
|
||||
|
||||
local concat = table.concat
|
||||
local tcp = ngx.socket.tcp
|
||||
local udp = ngx.socket.udp
|
||||
local timer_at = ngx.timer.at
|
||||
local ngx_log = ngx.log
|
||||
local ngx_sleep = ngx.sleep
|
||||
local type = type
|
||||
local pairs = pairs
|
||||
local tostring = tostring
|
||||
local debug = ngx.config.debug
|
||||
|
||||
local DEBUG = ngx.DEBUG
|
||||
local CRIT = ngx.CRIT
|
||||
|
||||
local MAX_PORT = 65535
|
||||
|
||||
|
||||
-- table.new(narr, nrec)
|
||||
local succ, new_tab = pcall(require, "table.new")
|
||||
if not succ then
|
||||
new_tab = function () return {} end
|
||||
end
|
||||
|
||||
local _M = new_tab(0, 5)
|
||||
|
||||
local is_exiting
|
||||
|
||||
if not ngx.config or not ngx.config.ngx_lua_version
|
||||
or ngx.config.ngx_lua_version < 9003 then
|
||||
|
||||
is_exiting = function() return false end
|
||||
|
||||
ngx_log(CRIT, "We strongly recommend you to update your ngx_lua module to "
|
||||
.. "0.9.3 or above. lua-resty-logger-socket will lose some log "
|
||||
.. "messages when Nginx reloads if it works with ngx_lua module "
|
||||
.. "below 0.9.3")
|
||||
else
|
||||
is_exiting = ngx.worker.exiting
|
||||
end
|
||||
|
||||
|
||||
_M._VERSION = '0.03'
|
||||
|
||||
-- user config
|
||||
local flush_limit = 4096 -- 4KB
|
||||
local drop_limit = 1048576 -- 1MB
|
||||
local timeout = 1000 -- 1 sec
|
||||
local host
|
||||
local port
|
||||
local ssl = false
|
||||
local ssl_verify = true
|
||||
local sni_host
|
||||
local path
|
||||
local max_buffer_reuse = 10000 -- reuse buffer for at most 10000
|
||||
-- times
|
||||
local periodic_flush = nil
|
||||
local need_periodic_flush = nil
|
||||
local sock_type = 'tcp'
|
||||
|
||||
-- internal variables
|
||||
local buffer_size = 0
|
||||
-- 2nd level buffer, it stores logs ready to be sent out
|
||||
local send_buffer = ""
|
||||
-- 1st level buffer, it stores incoming logs
|
||||
local log_buffer_data = new_tab(20000, 0)
|
||||
-- number of log lines in current 1st level buffer, starts from 0
|
||||
local log_buffer_index = 0
|
||||
|
||||
local last_error
|
||||
|
||||
local connecting
|
||||
local connected
|
||||
local exiting
|
||||
local retry_connect = 0
|
||||
local retry_send = 0
|
||||
local max_retry_times = 3
|
||||
local retry_interval = 100 -- 0.1s
|
||||
local pool_size = 10
|
||||
local flushing
|
||||
local logger_initted
|
||||
local counter = 0
|
||||
local ssl_session
|
||||
|
||||
local function _write_error(msg)
|
||||
last_error = msg
|
||||
end
|
||||
|
||||
local function _do_connect()
|
||||
local ok, err, sock
|
||||
|
||||
if not connected then
|
||||
if (sock_type == 'udp') then
|
||||
sock, err = udp()
|
||||
else
|
||||
sock, err = tcp()
|
||||
end
|
||||
|
||||
if not sock then
|
||||
_write_error(err)
|
||||
return nil, err
|
||||
end
|
||||
|
||||
sock:settimeout(timeout)
|
||||
end
|
||||
|
||||
-- "host"/"port" and "path" have already been checked in init()
|
||||
if host and port then
|
||||
if (sock_type == 'udp') then
|
||||
ok, err = sock:setpeername(host, port)
|
||||
else
|
||||
ok, err = sock:connect(host, port)
|
||||
end
|
||||
elseif path then
|
||||
ok, err = sock:connect("unix:" .. path)
|
||||
end
|
||||
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
return sock
|
||||
end
|
||||
|
||||
local function _do_handshake(sock)
|
||||
if not ssl then
|
||||
return sock
|
||||
end
|
||||
|
||||
local session, err = sock:sslhandshake(ssl_session, sni_host or host,
|
||||
ssl_verify)
|
||||
if not session then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
ssl_session = session
|
||||
return sock
|
||||
end
|
||||
|
||||
local function _connect()
|
||||
local err, sock
|
||||
|
||||
if connecting then
|
||||
if debug then
|
||||
ngx_log(DEBUG, "previous connection not finished")
|
||||
end
|
||||
return nil, "previous connection not finished"
|
||||
end
|
||||
|
||||
connected = false
|
||||
connecting = true
|
||||
|
||||
retry_connect = 0
|
||||
|
||||
while retry_connect <= max_retry_times do
|
||||
sock, err = _do_connect()
|
||||
|
||||
if sock then
|
||||
sock, err = _do_handshake(sock)
|
||||
if sock then
|
||||
connected = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if debug then
|
||||
ngx_log(DEBUG, "reconnect to the log server: ", err)
|
||||
end
|
||||
|
||||
-- ngx.sleep time is in seconds
|
||||
if not exiting then
|
||||
ngx_sleep(retry_interval / 1000)
|
||||
end
|
||||
|
||||
retry_connect = retry_connect + 1
|
||||
end
|
||||
|
||||
connecting = false
|
||||
if not connected then
|
||||
return nil, "try to connect to the log server failed after "
|
||||
.. max_retry_times .. " retries: " .. err
|
||||
end
|
||||
|
||||
return sock
|
||||
end
|
||||
|
||||
local function _prepare_stream_buffer()
|
||||
local packet = concat(log_buffer_data, "", 1, log_buffer_index)
|
||||
send_buffer = send_buffer .. packet
|
||||
|
||||
log_buffer_index = 0
|
||||
counter = counter + 1
|
||||
if counter > max_buffer_reuse then
|
||||
log_buffer_data = new_tab(20000, 0)
|
||||
counter = 0
|
||||
if debug then
|
||||
ngx_log(DEBUG, "log buffer reuse limit (" .. max_buffer_reuse
|
||||
.. ") reached, create a new \"log_buffer_data\"")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function _do_flush()
|
||||
local ok, err, sock, bytes
|
||||
local packet = send_buffer
|
||||
|
||||
sock, err = _connect()
|
||||
if not sock then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
bytes, err = sock:send(packet)
|
||||
if not bytes then
|
||||
-- "sock:send" always closes current connection on error
|
||||
return nil, err
|
||||
end
|
||||
|
||||
if debug then
|
||||
ngx.update_time()
|
||||
ngx_log(DEBUG, ngx.now(), ":log flush:" .. bytes .. ":" .. packet)
|
||||
end
|
||||
|
||||
if (sock_type ~= 'udp') then
|
||||
ok, err = sock:setkeepalive(0, pool_size)
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
|
||||
return bytes
|
||||
end
|
||||
|
||||
local function _need_flush()
|
||||
if buffer_size > 0 then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function _flush_lock()
|
||||
if not flushing then
|
||||
if debug then
|
||||
ngx_log(DEBUG, "flush lock acquired")
|
||||
end
|
||||
flushing = true
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function _flush_unlock()
|
||||
if debug then
|
||||
ngx_log(DEBUG, "flush lock released")
|
||||
end
|
||||
flushing = false
|
||||
end
|
||||
|
||||
local function _flush()
|
||||
local err
|
||||
|
||||
-- pre check
|
||||
if not _flush_lock() then
|
||||
if debug then
|
||||
ngx_log(DEBUG, "previous flush not finished")
|
||||
end
|
||||
-- do this later
|
||||
return true
|
||||
end
|
||||
|
||||
if not _need_flush() then
|
||||
if debug then
|
||||
ngx_log(DEBUG, "no need to flush:", log_buffer_index)
|
||||
end
|
||||
_flush_unlock()
|
||||
return true
|
||||
end
|
||||
|
||||
-- start flushing
|
||||
retry_send = 0
|
||||
if debug then
|
||||
ngx_log(DEBUG, "start flushing")
|
||||
end
|
||||
|
||||
local bytes
|
||||
while retry_send <= max_retry_times do
|
||||
if log_buffer_index > 0 then
|
||||
_prepare_stream_buffer()
|
||||
end
|
||||
|
||||
bytes, err = _do_flush()
|
||||
|
||||
if bytes then
|
||||
break
|
||||
end
|
||||
|
||||
if debug then
|
||||
ngx_log(DEBUG, "resend log messages to the log server: ", err)
|
||||
end
|
||||
|
||||
-- ngx.sleep time is in seconds
|
||||
if not exiting then
|
||||
ngx_sleep(retry_interval / 1000)
|
||||
end
|
||||
|
||||
retry_send = retry_send + 1
|
||||
end
|
||||
|
||||
_flush_unlock()
|
||||
|
||||
if not bytes then
|
||||
local err_msg = "try to send log messages to the log server "
|
||||
.. "failed after " .. max_retry_times .. " retries: "
|
||||
.. err
|
||||
_write_error(err_msg)
|
||||
return nil, err_msg
|
||||
else
|
||||
if debug then
|
||||
ngx_log(DEBUG, "send " .. bytes .. " bytes")
|
||||
end
|
||||
end
|
||||
|
||||
buffer_size = buffer_size - #send_buffer
|
||||
send_buffer = ""
|
||||
|
||||
return bytes
|
||||
end
|
||||
|
||||
local function _periodic_flush(premature)
|
||||
if premature then
|
||||
exiting = true
|
||||
end
|
||||
|
||||
if need_periodic_flush or exiting then
|
||||
-- no regular flush happened after periodic flush timer had been set
|
||||
if debug then
|
||||
ngx_log(DEBUG, "performing periodic flush")
|
||||
end
|
||||
_flush()
|
||||
else
|
||||
if debug then
|
||||
ngx_log(DEBUG, "no need to perform periodic flush: regular flush "
|
||||
.. "happened before")
|
||||
end
|
||||
need_periodic_flush = true
|
||||
end
|
||||
|
||||
timer_at(periodic_flush, _periodic_flush)
|
||||
end
|
||||
|
||||
local function _flush_buffer()
|
||||
local ok, err = timer_at(0, _flush)
|
||||
|
||||
need_periodic_flush = false
|
||||
|
||||
if not ok then
|
||||
_write_error(err)
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
|
||||
local function _write_buffer(msg, len)
|
||||
log_buffer_index = log_buffer_index + 1
|
||||
log_buffer_data[log_buffer_index] = msg
|
||||
|
||||
buffer_size = buffer_size + len
|
||||
|
||||
|
||||
return buffer_size
|
||||
end
|
||||
|
||||
function _M.init(user_config)
|
||||
if (type(user_config) ~= "table") then
|
||||
return nil, "user_config must be a table"
|
||||
end
|
||||
|
||||
for k, v in pairs(user_config) do
|
||||
if k == "host" then
|
||||
if type(v) ~= "string" then
|
||||
return nil, '"host" must be a string'
|
||||
end
|
||||
host = v
|
||||
elseif k == "port" then
|
||||
if type(v) ~= "number" then
|
||||
return nil, '"port" must be a number'
|
||||
end
|
||||
if v < 0 or v > MAX_PORT then
|
||||
return nil, ('"port" out of range 0~%s'):format(MAX_PORT)
|
||||
end
|
||||
port = v
|
||||
elseif k == "path" then
|
||||
if type(v) ~= "string" then
|
||||
return nil, '"path" must be a string'
|
||||
end
|
||||
path = v
|
||||
elseif k == "sock_type" then
|
||||
if type(v) ~= "string" then
|
||||
return nil, '"sock_type" must be a string'
|
||||
end
|
||||
if v ~= "tcp" and v ~= "udp" then
|
||||
return nil, '"sock_type" must be "tcp" or "udp"'
|
||||
end
|
||||
sock_type = v
|
||||
elseif k == "flush_limit" then
|
||||
if type(v) ~= "number" or v < 0 then
|
||||
return nil, 'invalid "flush_limit"'
|
||||
end
|
||||
flush_limit = v
|
||||
elseif k == "drop_limit" then
|
||||
if type(v) ~= "number" or v < 0 then
|
||||
return nil, 'invalid "drop_limit"'
|
||||
end
|
||||
drop_limit = v
|
||||
elseif k == "timeout" then
|
||||
if type(v) ~= "number" or v < 0 then
|
||||
return nil, 'invalid "timeout"'
|
||||
end
|
||||
timeout = v
|
||||
elseif k == "max_retry_times" then
|
||||
if type(v) ~= "number" or v < 0 then
|
||||
return nil, 'invalid "max_retry_times"'
|
||||
end
|
||||
max_retry_times = v
|
||||
elseif k == "retry_interval" then
|
||||
if type(v) ~= "number" or v < 0 then
|
||||
return nil, 'invalid "retry_interval"'
|
||||
end
|
||||
-- ngx.sleep time is in seconds
|
||||
retry_interval = v
|
||||
elseif k == "pool_size" then
|
||||
if type(v) ~= "number" or v < 0 then
|
||||
return nil, 'invalid "pool_size"'
|
||||
end
|
||||
pool_size = v
|
||||
elseif k == "max_buffer_reuse" then
|
||||
if type(v) ~= "number" or v < 0 then
|
||||
return nil, 'invalid "max_buffer_reuse"'
|
||||
end
|
||||
max_buffer_reuse = v
|
||||
elseif k == "periodic_flush" then
|
||||
if type(v) ~= "number" or v < 0 then
|
||||
return nil, 'invalid "periodic_flush"'
|
||||
end
|
||||
periodic_flush = v
|
||||
elseif k == "ssl" then
|
||||
if type(v) ~= "boolean" then
|
||||
return nil, '"ssl" must be a boolean value'
|
||||
end
|
||||
ssl = v
|
||||
elseif k == "ssl_verify" then
|
||||
if type(v) ~= "boolean" then
|
||||
return nil, '"ssl_verify" must be a boolean value'
|
||||
end
|
||||
ssl_verify = v
|
||||
elseif k == "sni_host" then
|
||||
if type(v) ~= "string" then
|
||||
return nil, '"sni_host" must be a string'
|
||||
end
|
||||
sni_host = v
|
||||
end
|
||||
end
|
||||
|
||||
if not (host and port) and not path then
|
||||
return nil, "no logging server configured. \"host\"/\"port\" or "
|
||||
.. "\"path\" is required."
|
||||
end
|
||||
|
||||
|
||||
if (flush_limit >= drop_limit) then
|
||||
return nil, "\"flush_limit\" should be < \"drop_limit\""
|
||||
end
|
||||
|
||||
flushing = false
|
||||
exiting = false
|
||||
connecting = false
|
||||
|
||||
connected = false
|
||||
retry_connect = 0
|
||||
retry_send = 0
|
||||
|
||||
logger_initted = true
|
||||
|
||||
if periodic_flush then
|
||||
if debug then
|
||||
ngx_log(DEBUG, "periodic flush enabled for every "
|
||||
.. periodic_flush .. " seconds")
|
||||
end
|
||||
need_periodic_flush = true
|
||||
timer_at(periodic_flush, _periodic_flush)
|
||||
end
|
||||
|
||||
return logger_initted
|
||||
end
|
||||
|
||||
function _M.log(msg)
|
||||
if not logger_initted then
|
||||
return nil, "not initialized"
|
||||
end
|
||||
|
||||
local bytes
|
||||
|
||||
if type(msg) ~= "string" then
|
||||
msg = tostring(msg)
|
||||
end
|
||||
|
||||
local msg_len = #msg
|
||||
|
||||
if (debug) then
|
||||
ngx.update_time()
|
||||
ngx_log(DEBUG, ngx.now(), ":log message length: " .. msg_len)
|
||||
end
|
||||
|
||||
-- response of "_flush_buffer" is not checked, because it writes
|
||||
-- error buffer
|
||||
if (is_exiting()) then
|
||||
exiting = true
|
||||
_write_buffer(msg, msg_len)
|
||||
_flush_buffer()
|
||||
if (debug) then
|
||||
ngx_log(DEBUG, "Nginx worker is exiting")
|
||||
end
|
||||
bytes = 0
|
||||
elseif (msg_len + buffer_size < flush_limit) then
|
||||
_write_buffer(msg, msg_len)
|
||||
bytes = msg_len
|
||||
elseif (msg_len + buffer_size <= drop_limit) then
|
||||
_write_buffer(msg, msg_len)
|
||||
_flush_buffer()
|
||||
bytes = msg_len
|
||||
else
|
||||
_flush_buffer()
|
||||
if (debug) then
|
||||
ngx_log(DEBUG, "logger buffer is full, this log message will be "
|
||||
.. "dropped")
|
||||
end
|
||||
bytes = 0
|
||||
--- this log message doesn't fit in buffer, drop it
|
||||
end
|
||||
|
||||
if last_error then
|
||||
local err = last_error
|
||||
last_error = nil
|
||||
return bytes, err
|
||||
end
|
||||
|
||||
return bytes
|
||||
end
|
||||
|
||||
function _M.initted()
|
||||
return logger_initted
|
||||
end
|
||||
|
||||
_M.flush = _flush
|
||||
|
||||
return _M
|
||||
|
9
waf.lua
9
waf.lua
|
@ -1,8 +1,12 @@
|
|||
local content_length=tonumber(ngx.req.get_headers()['content-length'])
|
||||
local method=ngx.req.get_method()
|
||||
--ngx_lua如果是0.9.2以上版本,建议正则过滤函数改为ngx.re.find,匹配效率会提高三倍左右。
|
||||
local ngxmatch=ngx.re.match
|
||||
--local ngxmatch=ngx.re.find
|
||||
if whiteip() then
|
||||
elseif blockip() then
|
||||
--检测攻击ip是否被拦截。
|
||||
elseif denyhackip(1) then
|
||||
elseif denycc() then
|
||||
elseif ngx.var.http_Acunetix_Aspect then
|
||||
ngx.exit(444)
|
||||
|
@ -42,7 +46,7 @@ elseif PostCheck then
|
|||
return true
|
||||
end
|
||||
size = size + len(data)
|
||||
local m = ngxmatch(data,[[Content-Disposition: form-data;(.+)filename="(.+)\\.(.*)"]],'ijo')
|
||||
local m = ngxmatch(data,[[Content-Disposition: form-data;(.+)filename="(.+)\.(.*)"]],'ijo')
|
||||
if m then
|
||||
fileExtCheck(m[3])
|
||||
filetranslate = true
|
||||
|
@ -82,7 +86,8 @@ elseif PostCheck then
|
|||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
return
|
||||
end
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
^/123/$
|
||||
site:^www\.baidu\.com/whiteurl/
|
||||
|
|
Loading…
Reference in New Issue