\
@@ -1394,7 +1394,7 @@ function siteWafConfig(siteName, type) {
type: 1,
title: "网站配置【" + siteName + "】",
area: ['700px', '500px'],
- closeBtn: 2,
+ closeBtn: 1,
shadeClose: false,
content: '
'
});
diff --git a/plugins/op_waf/t/cc.py b/plugins/op_waf/t/cc.py
deleted file mode 100644
index 3ad1ef97d..000000000
--- a/plugins/op_waf/t/cc.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# coding:utf-8
-
-import sys
-import io
-import os
-import time
-import json
diff --git a/plugins/op_waf/t/index.py b/plugins/op_waf/t/index.py
index b0cccb57a..2d2301d18 100644
--- a/plugins/op_waf/t/index.py
+++ b/plugins/op_waf/t/index.py
@@ -6,14 +6,168 @@ import os
import time
import json
+import os
+import sys
+import time
+import string
+import json
+import hashlib
+import shlex
+import datetime
+import subprocess
+import re
+from random import Random
+
+
+TEST_URL = "http://t1.cn/"
+# TEST_URL = "https://www.zzzvps.com/"
+
+
+def httpGet(url, timeout=10):
+ import urllib.request
+
+ try:
+ req = urllib.request.urlopen(url, timeout=timeout)
+ result = req.read().decode('utf-8')
+ return result
+
+ except Exception as e:
+ return str(e)
+
+
+def httpGet__UA(url, ua, timeout=10):
+ import urllib.request
+ headers = {'user-agent': ua}
+ try:
+ req = urllib.request.Request(url, headers=headers)
+ response = urllib.request.urlopen(req)
+ result = response.read().decode('utf-8')
+ return result
+
+ except Exception as e:
+ return str(e)
+
+
+def httpPost(url, data, timeout=10):
+ """
+ 发送POST请求
+ @url 被请求的URL地址(必需)
+ @data POST参数,可以是字符串或字典(必需)
+ @timeout 超时时间默认60秒
+ return string
+ """
+ if sys.version_info[0] == 2:
+ try:
+ import urllib
+ import urllib2
+ import ssl
+ ssl._create_default_https_context = ssl._create_unverified_context
+ data = urllib.urlencode(data)
+ req = urllib2.Request(url, data)
+ response = urllib2.urlopen(req, timeout=timeout)
+ return response.read()
+ except Exception as ex:
+ return str(ex)
+ else:
+ try:
+ import urllib.request
+ import ssl
+ try:
+ ssl._create_default_https_context = ssl._create_unverified_context
+ except:
+ pass
+ data = urllib.parse.urlencode(data).encode('utf-8')
+ req = urllib.request.Request(url, data)
+ response = urllib.request.urlopen(req, timeout=timeout)
+ result = response.read()
+ if type(result) == bytes:
+ result = result.decode('utf-8')
+ return result
+ except Exception as ex:
+ return str(ex)
+
+
+def test_Dir():
+ '''
+ 目录保存
+ '''
+ url = TEST_URL + '?t=../etc/passwd'
+ print("args test start")
+ url_val = httpGet(url, 10)
+ # print(url_val)
+ print("args test end")
+
+
+def test_UA():
+ '''
+ user-agent 过滤
+ '''
+ url = TEST_URL
+ print("user-agent test start")
+ url_val = httpGet__UA(url, 'ApacheBench')
+ print(url_val)
+ print("user-agent test end")
+
+
+def test_POST():
+ '''
+ user-agent 过滤
+ '''
+ url = TEST_URL
+ print("POST test start")
+ url_val = httpPost(url, {'data': "substr($mmsss,0,1)"})
+ # url_val = httpPost(url, {'data': "123123"})
+ print(url_val)
+ print("POST test end")
+
+
+def test_scan():
+ '''
+ 目录保存
+ '''
+ url = TEST_URL + '/acunetix_wvs_security_test?t=1'
+ print("scan test start")
+ url_val = httpGet(url, 10)
+ print(url_val)
+ print("scan test end")
+
+
+def test_CC():
+ '''
+ 目录保存
+ '''
+ url = TEST_URL + 'ok.txt'
+ print("CC test start")
+
+ for x in range(122):
+ url_val = httpGet(url, 10)
+ print(url_val)
+
+ print("CC test end")
+
+
+def test_url_ext():
+ '''
+ 目录保存
+ '''
+ url = TEST_URL + 't.sql'
+ print("url_ext start")
+ url_val = httpGet(url, 10)
+ print(url_val)
+
+ print("url_ext end")
-TEST_URL = "t1.cn"
+def test_start():
+ # test_Dir()
+ # test_UA()
+ # test_POST()
+ # test_scan()
+ # test_CC()
+ test_url_ext()
-def run():
- print('op lua run ok')
if __name__ == "__main__":
- if len(sys.argv) > 1:
- if action == "run":
- run()
+ os.system('cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/op_waf && sh install.sh uninstall 0.1 && sh install.sh install 0.1')
+ os.system('cd /Users/midoks/Desktop/mwdev/server/mdserver-web/ && python3 plugins/openresty/index.py stop && python3 plugins/openresty/index.py start')
+ test_start()
diff --git a/plugins/op_waf/t/test.sh b/plugins/op_waf/t/test.sh
index 191618015..c614871c0 100755
--- a/plugins/op_waf/t/test.sh
+++ b/plugins/op_waf/t/test.sh
@@ -2,6 +2,8 @@
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
+# yum -y install httpd-tools
+# ab -c 1000 -n 1000000 http://xx.xx.xx/
python3 index.py
diff --git a/plugins/op_waf/waf/config.json b/plugins/op_waf/waf/config.json
index 92bbed594..c9835d484 100755
--- a/plugins/op_waf/waf/config.json
+++ b/plugins/op_waf/waf/config.json
@@ -1 +1 @@
-{"reqfile_path": "{$WAF_PATH}/html", "retry": {"retry_time": 180, "is_open_global": 0, "retry": 6, "retry_cycle": 60}, "log": true, "scan": {"status": 444, "ps": "\u8fc7\u6ee4\u5e38\u89c1\u626b\u63cf\u6d4b\u8bd5\u5de5\u5177\u7684\u6e17\u900f\u6d4b\u8bd5", "open": true, "reqfile": ""}, "cc": {"status": 444, "ps": "\u8fc7\u8651CC\u653b\u51fb", "limit": 120, "endtime": 300, "open": true, "reqfile": "", "cycle": 60}, "get": {"status": 403, "ps": "\u8fc7\u6ee4uri\u3001uri\u53c2\u6570\u4e2d\u5e38\u89c1sql\u6ce8\u5165\u3001xss\u7b49\u653b\u51fb", "open": true, "reqfile": "get.html"}, "log_save": 30, "user-agent": {"status": 403, "ps": "\u901a\u5e38\u7528\u4e8e\u8fc7\u6ee4\u6d4f\u89c8\u5668\u3001\u8718\u86db\u53ca\u4e00\u4e9b\u81ea\u52a8\u626b\u63cf\u5668", "open": true, "reqfile": "user_agent.html"}, "other": {"status": 403, "ps": "\u5176\u5b83\u975e\u901a\u7528\u8fc7\u6ee4", "reqfile": "other.html"}, "cookie": {"status": 403, "ps": "\u8fc7\u6ee4\u5229\u7528Cookie\u53d1\u8d77\u7684\u6e17\u900f\u653b\u51fb", "open": true, "reqfile": "cookie.html"}, "logs_path": "/www/wwwlogs/btwaf", "post": {"status": 403, "ps": "\u8fc7\u6ee4POST\u53c2\u6570\u4e2d\u5e38\u89c1sql\u6ce8\u5165\u3001xss\u7b49\u653b\u51fb", "open": true, "reqfile": "post.html"}, "open": true}
\ No newline at end of file
+{"reqfile_path": "{$WAF_PATH}/html", "retry": {"retry_time": 180, "is_open_global": 0, "retry": 6, "retry_cycle": 60}, "log": true, "scan": {"status": 444, "ps": "\u8fc7\u6ee4\u5e38\u89c1\u626b\u63cf\u6d4b\u8bd5\u5de5\u5177\u7684\u6e17\u900f\u6d4b\u8bd5", "open": true, "reqfile": ""}, "cc": {"status": 444, "ps": "\u8fc7\u8651CC\u653b\u51fb", "limit": 120, "endtime": 300, "open": true, "reqfile": "", "cycle": 60}, "get": {"status": 403, "ps": "\u8fc7\u6ee4uri\u3001uri\u53c2\u6570\u4e2d\u5e38\u89c1sql\u6ce8\u5165\u3001xss\u7b49\u653b\u51fb", "open": true, "reqfile": "get.html"}, "log_save": 30, "user-agent": {"status": 403, "ps": "\u901a\u5e38\u7528\u4e8e\u8fc7\u6ee4\u6d4f\u89c8\u5668\u3001\u8718\u86db\u53ca\u4e00\u4e9b\u81ea\u52a8\u626b\u63cf\u5668", "open": true, "reqfile": "user_agent.html"}, "other": {"status": 403, "ps": "\u5176\u5b83\u975e\u901a\u7528\u8fc7\u6ee4", "reqfile": "other.html"}, "cookie": {"status": 403, "ps": "\u8fc7\u6ee4\u5229\u7528Cookie\u53d1\u8d77\u7684\u6e17\u900f\u653b\u51fb", "open": true, "reqfile": "cookie.html"}, "logs_path": "/www/wwwlogs/waf", "post": {"status": 403, "ps": "\u8fc7\u6ee4POST\u53c2\u6570\u4e2d\u5e38\u89c1sql\u6ce8\u5165\u3001xss\u7b49\u653b\u51fb", "open": true, "reqfile": "post.html"}, "open": true}
\ No newline at end of file
diff --git a/plugins/op_waf/waf/lua/common.lua b/plugins/op_waf/waf/lua/common.lua
index f04c1686b..ed2c20b2e 100644
--- a/plugins/op_waf/waf/lua/common.lua
+++ b/plugins/op_waf/waf/lua/common.lua
@@ -1,26 +1,89 @@
local setmetatable = setmetatable
-local _M = { _VERSION = '0.01' }
+local _M = { _VERSION = '0.02' }
local mt = { __index = _M }
+
local json = require "cjson"
local ngx_match = ngx.re.find
+local debug_mode = false
+
+local waf_root = "{$WAF_ROOT}"
+local cpath = waf_root.."/waf/"
+local logdir = waf_root.."/logs/"
+local rpath = cpath.."/rule/"
+
+function _M.new(self)
-function _M.new(self, cpath, rpath, logdir)
- -- ngx.log(ngx.ERR,"read:"..cpath..",rpath:"..rpath)
- local opt = {
- cpath = cpath,
- rpath = rpath,
- logdir = logdir,
- config = '',
- site_config = '',
- params = nil
+
+ local self = {
+ waf_root = waf_root,
+ cpath = cpath,
+ rpath = rpath,
+ logdir = logdir,
+ config = '',
+ site_config = '',
+ server_name = '',
+ params = nil
}
- local p = setmetatable(opt, mt)
- return p
+
+ return setmetatable(self, mt)
+end
+
+
+function _M.setDebug(self, mode)
+ debug_mode = mode
+end
+
+
+-- 调试方式
+function _M.D(self, msg)
+
+ if not debug_mode then return true end
+
+ local _msg = ''
+ if type(msg) == 'table' then
+ for key, val in pairs(msg) do
+ _msg = tostring( key)..':'.."\n"
+ end
+ elseif type(msg) == 'string' then
+ _msg = msg
+ elseif type(msg) == 'nil' then
+ _msg = 'nil'
+ else
+ _msg = msg
+ end
+
+
+ local fp = io.open(waf_root.."/debug.log", "ab")
+ if fp == nil then
+ return nil
+ end
+
+ local localtime = os.date("%Y-%m-%d %H:%M:%S")
+ if server_name then
+ fp:write(tostring(_msg) .. "\n")
+ else
+ fp:write(localtime..":"..tostring(_msg) .. "\n")
+ end
+
+ fp:flush()
+ fp:close()
+ return true
end
+local function write_file_clear(filename, body)
+ fp = io.open(filename,'w')
+ if fp == nil then
+ return nil
+ end
+ fp:write(body)
+ fp:flush()
+ fp:close()
+ return true
+end
+
function _M.setConfData( self, config, site_config )
self.config = config
self.site_config = site_config
@@ -94,6 +157,10 @@ function _M.compare_ip(self,ips)
end
+function _M.to_json(self, msg)
+ return json.encode(msg)
+end
+
function _M.return_message(self, status, msg)
ngx.header.content_type = "application/json;"
ngx.status = status
@@ -136,20 +203,15 @@ function _M.write_file(self, filename, body)
return true
end
+
function _M.write_file_clear(self, filename, body)
- fp = io.open(filename,'w')
- if fp == nil then
- return nil
- end
- fp:write(body)
- fp:flush()
- fp:close()
- return true
+ return write_file_clear(filename, body)
end
function _M.write_drop_ip(self, is_drop, drop_time)
- local filename = self.cpath .. 'drop_ip.log'
+ local filename = self.logdir .. 'drop_ip.log'
+
local fp = io.open(filename,'ab')
local server_name = self.params["server_name"]
local ip = self.params["server_name"]
@@ -234,11 +296,21 @@ function _M.read_file(self, name)
end
function _M.read_file_table( self, name )
- return self:select_rule(self:read_file('args'))
+ return self:select_rule(self:read_file(name))
end
+local function timer_at_inc_log(premature)
+ local total_path = cpath .. 'total.json'
+ local tbody = ngx.shared.limit:get(total_path)
+ if not tbody then
+ return false
+ end
+ return write_file_clear(total_path,tbody)
+end
+
function _M.inc_log(self, name, rule)
+
local server_name = self.params['server_name']
local total_path = self.cpath .. 'total.json'
local tbody = ngx.shared.limit:get(total_path)
@@ -246,7 +318,10 @@ function _M.inc_log(self, name, rule)
tbody = self:read_file_body(total_path)
if not tbody then return false end
end
+
local total = json.decode(tbody)
+
+ -- 开始计算
if not total['sites'] then total['sites'] = {} end
if not total['sites'][server_name] then total['sites'][server_name] = {} end
if not total['sites'][server_name][name] then total['sites'][server_name][name] = 0 end
@@ -256,13 +331,15 @@ function _M.inc_log(self, name, rule)
total['total'] = total['total'] + 1
total['sites'][server_name][name] = total['sites'][server_name][name] + 1
total['rules'][name] = total['rules'][name] + 1
+
local total_log = json.encode(total)
if not total_log then return false end
+
ngx.shared.limit:set(total_path,total_log)
- if not ngx.shared.limit:get('mw_waf_timeout') then
- self:write_file_clear(total_path,total_log)
- ngx.shared.limit:set('mw_waf_timeout',1,5)
- end
+
+ -- 异步执行
+ ngx.timer.at(1, timer_at_inc_log)
+
end
@@ -289,9 +366,66 @@ function _M.get_server_name(self)
end
--- function _M.get_sn(self)
--- retun string.gsub(self:get_server_name(),'_','.')
--- end
+
+function _M.is_ngx_match_orgin(self,rule,match, sign)
+ if ngx_match(ngx.unescape_uri(match), rule,"isjo") then
+ error_rule = rule .. ' >> ' .. sign .. ':' .. match
+ return true
+ end
+ return false
+end
+
+
+function _M.ngx_match_string(self, rule, content,sign)
+ local t = self:is_ngx_match_orgin(rule, content, sign)
+ if t then
+ return true
+ end
+
+ return false
+end
+
+function _M.ngx_match_list(self, rules, content)
+ for i,rule in ipairs(rules)
+ do
+ if rule[1] == 1 then
+ local t = self:is_ngx_match_orgin(rule[2], content, rule[3])
+ if t then
+ return true
+ end
+ end
+ end
+ return false
+end
+
+function _M.is_ngx_match_ua(self, rules, content)
+ -- ngx.header.content_type = "text/html"
+ for i,rule in ipairs(rules)
+ do
+ -- 开启的规则,才匹配。
+ if rule[1] == 1 then
+ local t = self:is_ngx_match_orgin(rule[2], content, rule[3])
+ if t then
+ return true
+ end
+ end
+ end
+ return false
+end
+
+function _M.is_ngx_match_post(self, rules, content)
+ for i,rule in ipairs(rules)
+ do
+ -- 开启的规则,才匹配。
+ if rule[1] == 1 then
+ local t = self:is_ngx_match_orgin(rule[2],content, rule[3])
+ if t then
+ return true
+ end
+ end
+ end
+ return false
+end
function _M.is_ngx_match(self, rules, sbody, rule_name)
@@ -341,6 +475,7 @@ end
function _M.write_log(self, name, rule)
+
local ip = self.params['ip']
local retry = self.config['retry']['retry']
local retry_time = self.config['retry']['retry_time']
@@ -352,6 +487,7 @@ function _M.write_log(self, name, rule)
else
ngx.shared.drop_ip:set(ip,1,retry_cycle)
end
+
if self.config['log'] ~= true or self:is_site_config('log') ~= true then return false end
local method = ngx.req.get_method()
if error_rule then
@@ -384,10 +520,13 @@ end
function _M.get_client_ip(self)
local client_ip = "unknown"
+ local server_name = self.params['server_name']
+ -- self:D("fff..."..client_ip..server_name)
if self.site_config[server_name] then
if self.site_config[server_name]['cdn'] then
for _,v in ipairs(self.site_config[server_name]['cdn_header'])
do
+ -- C:D("vv:"..v..tostring(request_header[v]))
if request_header[v] ~= nil and request_header[v] ~= "" then
local header_tmp = request_header[v]
if type(header_tmp) == "table" then header_tmp = header_tmp[1] end
@@ -408,7 +547,6 @@ end
function _M.is_site_config(self,cname)
- local server_name = self.params["server_name"]
if self.site_config[server_name] ~= nil then
if cname == 'cc' then
return self.site_config[server_name][cname]['open']
diff --git a/plugins/op_waf/waf/lua/init.lua b/plugins/op_waf/waf/lua/init.lua
index f4311e7d9..b03727aab 100644
--- a/plugins/op_waf/waf/lua/init.lua
+++ b/plugins/op_waf/waf/lua/init.lua
@@ -1,65 +1,55 @@
-
-local cpath = "{$WAF_PATH}/"
-local rpath = "{$WAF_PATH}/rule/"
-local logdir = "{$ROOT_PATH}/wwwlogs/waf/"
local json = require "cjson"
local ngx_match = ngx.re.find
-local _C = require "common"
-local C = _C:new(cpath, rpath, logdir)
+local __C = require "common"
+local C = __C:new()
+
+local waf_root = "{$WAF_ROOT}"
-config = C:read_file_body_decode(cpath .. 'config.json')
-local site_config = C:read_file_body_decode(cpath .. 'site.json')
+config = C:read_file_body_decode(waf_root.."/waf/"..'config.json')
+local site_config = C:read_file_body_decode(waf_root.."/waf/"..'site.json')
C:setConfData(config, site_config)
--- D func
-local function D(msg)
- local _msg = ''
- if type(msg) == 'table' then
- for key, val in pairs(msg) do
- _msg = key..':'..val.."\n"
- end
- elseif type(msg) == 'string' then
- _msg = msg
- elseif type(msg) == 'nil' then
- _msg = 'nil'
- else
- _msg = msg
- end
- if not debug_mode then return true end
- local fp = io.open(cpath..'debug.log', 'ab')
- if fp == nil then
- return nil
- end
- local localtime = os.date("%Y-%m-%d %H:%M:%S")
- if server_name then
- fp:write(tostring(_msg) .. "\n")
- else
- fp:write(localtime..":"..tostring(_msg) .. "\n")
- end
- fp:flush()
- fp:close()
- return true
-end
+local get_html = C:read_file_body(config["reqfile_path"] .. '/' .. config["get"]["reqfile"])
+local post_html = C:read_file_body(config["reqfile_path"] .. '/' .. config["post"]["reqfile"])
+local user_agent_html = C:read_file_body(config["reqfile_path"] .. '/' .. config["user-agent"]["reqfile"])
+local args_rules = C:read_file_table('args')
+local ip_white_rules = C:read_file('ip_white')
+local ip_black_rules = C:read_file('ip_black')
+local scan_black_rules = C:read_file('scan_black')
+local user_agent_rules = C:read_file('user_agent')
+local post_rules = C:read_file('post')
+local cookie_rules = C:read_file('cookie')
+
+
+local server_name = string.gsub(C:get_server_name(),'_','.')
+
+
+-- C:D("sss:"..C:get_server_name())
function initParams()
local data = {}
- data['ip'] = C:get_client_ip()
- data['ipn'] = C:arrip(data['ip'])
+ data['server_name'] = server_name
+ -- data['ip'] = C:get_client_ip()
+ -- data['ipn'] = C:arrip(data['ip'])
data['request_header'] = ngx.req.get_headers()
data['uri'] = ngx.unescape_uri(ngx.var.uri)
- data['server_name'] = string.gsub(C:get_server_name(),'_','.')
data['uri_request_args'] = ngx.req.get_uri_args()
data['method'] = ngx.req.get_method()
data['request_uri'] = ngx.var.request_uri
+ data['cookie'] = ngx.var.http_cookie
return data
end
local params = initParams()
C:setParams(params)
+C:setDebug(true)
-
+local server_name = params["server_name"]
+params['ip'] = C:get_client_ip()
+params['ipn'] = C:arrip(params['ip'])
+C:D(server_name)
function get_return_state(rstate,rmsg)
result = {}
@@ -102,20 +92,20 @@ function save_ip_on(data)
end
end
-function remove_btwaf_drop_ip()
+function remove_waf_drop_ip()
if not uri_request_args['ip'] or not C:is_ipaddr(uri_request_args['ip']) then return get_return_state(true,'格式错误') end
if ngx.shared.btwaf:get(cpath2 .. 'stop_ip') then
ret=ngx.shared.btwaf:get(cpath2 .. 'stop_ip')
ip_data=json.decode(ret)
- result=is_chekc_table(ip_data,uri_request_args['ip'])
+ result = is_chekc_table(ip_data,uri_request_args['ip'])
os.execute("sleep " .. 0.6)
ret2=ngx.shared.btwaf:get(cpath2 .. 'stop_ip')
- ip_data2=json.decode(ret2)
+ ip_data2 = json.decode(ret2)
if result == 3 then
for k,v in pairs(ip_data2)
do
if uri_request_args['ip'] == v['ip'] then
- v['time']=0
+ v['time'] = 0
end
end
end
@@ -125,7 +115,7 @@ function remove_btwaf_drop_ip()
return get_return_state(true,uri_request_args['ip'] .. '已解封')
end
-function clean_btwaf_drop_ip()
+function clean_waf_drop_ip()
if ngx.shared.btwaf:get(cpath2 .. 'stop_ip') then
ret2=ngx.shared.btwaf:get(cpath2 .. 'stop_ip')
ip_data2=json.decode(ret2)
@@ -155,15 +145,7 @@ function min_route()
end
end
-local get_html = C:read_file_body(config["reqfile_path"] .. '/' .. config["get"]["reqfile"])
-local post_html = C:read_file_body(config["reqfile_path"] .. '/' .. config["post"]["reqfile"])
-local user_agent_html = C:read_file_body(config["reqfile_path"] .. '/' .. config["user-agent"]["reqfile"])
-local args_rules = C:read_file_table('args')
-local ip_white_rules = C:read_file('ip_white')
-local ip_black_rules = C:read_file('ip_black')
-local scan_black_rules = C:read_file('scan_black')
-
-function waf_args()
+function waf_get_args()
if not config['get']['open'] or not C:is_site_config('get') then return false end
if C:is_ngx_match(args_rules, params['uri_request_args'],'args') then
C:write_log('args','regular')
@@ -196,38 +178,55 @@ function waf_ip_black()
end
-function waf_drop()
- local count,_ = ngx.shared.drop_ip:get(ip)
- if not count then return false end
- if count > config['retry'] then
- ngx.exit(config['cc']['status'])
+function waf_user_agent()
+ -- user_agent 过滤
+ if not config['user-agent']['open'] or not C:is_site_config('user-agent') then return false end
+ if C:is_ngx_match_ua(user_agent_rules,params['request_header']['user-agent']) then
+ C:write_log('user_agent','regular')
+ C:return_html(config['user-agent']['status'],user_agent_html)
return true
end
return false
end
-function waf_user_agent()
- if not config['user-agent']['open'] or not C:is_site_config('user-agent') then return false end
- if C:is_ngx_match(user_agent_rules,params['request_header']['user-agent'],'user_agent') then
- C:write_log('user_agent','regular')
- C:return_html(config['user-agent']['status'],user_agent_html)
+function waf_drop()
+ local count , _ = ngx.shared.drop_ip:get(ip)
+ if not count then return false end
+ if count > config['retry'] then
+ ngx.exit(config['cc']['status'])
return true
end
return false
end
-function cc()
+function waf_cc()
local ip = params['ip']
+
+ local ip_lock = ngx.shared.drop_ip:get(ip)
+ if ip_lock then
+ if ip_lock > 0 then
+ ngx.exit(config['cc']['status'])
+ return true
+ end
+ end
+
+ if not config['cc']['open'] or not C:is_site_config('cc') then return false end
+
+
local request_uri = params['request_uri']
local endtime = config['cc']['endtime']
- if not config['cc']['open'] or not site_cc then return false end
local token = ngx.md5(ip .. '_' .. request_uri)
- local count,_ = ngx.shared.limit:get(token)
+ local count = ngx.shared.limit:get(token)
+
+ local limit = config['cc']['limit']
+ local cycle = config['cc']['cycle']
+
if count then
- if count > limit then
- local safe_count,_ = ngx.shared.drop_sum:get(ip)
+ if count > limit then
+
+ local safe_count, _ = ngx.shared.drop_sum:get(ip)
if not safe_count then
ngx.shared.drop_sum:set(ip,1,86400)
safe_count = 1
@@ -236,23 +235,22 @@ function cc()
end
local lock_time = (endtime * safe_count)
if lock_time > 86400 then lock_time = 86400 end
- ngx.shared.drop_ip:set(ip,retry+1,lock_time)
+
+ -- lock_time = 10
+ ngx.shared.drop_ip:set(ip,1,lock_time)
+
C:write_log('cc',cycle..'秒内累计超过'..limit..'次请求,封锁' .. lock_time .. '秒')
C:write_drop_ip('cc',lock_time)
- if not server_name then
- insert_ip_list(ip,lock_time,os.time(),'1111')
- else
- insert_ip_list(ip,lock_time,os.time(),server_name)
- end
-
ngx.exit(config['cc']['status'])
return true
else
ngx.shared.limit:incr(token,1)
end
else
- ngx.shared.limit:set(token,1,cycle)
+ ngx.shared.drop_sum:set(ip,1,86400)
+ ngx.shared.limit:set(token, 1, cycle)
end
+ return false
end
--强制验证是否使用正常浏览器访问网站
@@ -287,20 +285,25 @@ end
function waf_scan_black()
+ -- 扫描软件禁止
if not config['scan']['open'] or not C:is_site_config('scan') then return false end
- if C:is_ngx_match(scan_black_rules['cookie'],params["request_header"]["cookie"],false) then
- C:write_log('scan','regular')
- ngx.exit(config['scan']['status'])
- return true
+ if not params["cookie"] then
+ if C:ngx_match_string(scan_black_rules['cookie'], tostring(params["cookie"]),'scan') then
+ C:write_log('scan','regular')
+ ngx.exit(config['scan']['status'])
+ return true
+ end
end
- if C:is_ngx_match(scan_black_rules['args'],params["request_uri"],false) then
+
+ if C:ngx_match_string(scan_black_rules['args'], params["request_uri"], 'scan') then
C:write_log('scan','regular')
ngx.exit(config['scan']['status'])
return true
end
+
for key,value in pairs(params["request_header"])
do
- if C:is_ngx_match(scan_black_rules['header'], key, false) then
+ if C:ngx_match_string(scan_black_rules['header'], key, 'scan') then
C:write_log('scan','regular')
ngx.exit(config['scan']['status'])
return true
@@ -309,20 +312,9 @@ function waf_scan_black()
return false
end
-function waf_post_referer()
- if params['method'] ~= "POST" then return false end
- if C:is_ngx_match(referer_local, params['request_header']['Referer'],'post') then
- C:write_log('post_referer','regular')
- C:return_html(config['post']['status'],post_html)
- return true
- end
- return false
-end
-
function waf_post()
if not config['post']['open'] or not C:is_site_config('post') then return false end
if params['method'] ~= "POST" then return false end
- if waf_post_referer() then return true end
content_length = tonumber(params["request_header"]['content-length'])
max_len = 640 * 1020000
if content_length > max_len then return false end
@@ -333,7 +325,19 @@ function waf_post()
return false
end
- if C:is_ngx_match(post_rules,request_args,'post') then
+ for key, val in pairs(request_args) do
+ if type(val) == "table" then
+ if type(val[1]) == "boolean" then
+ return false
+ end
+ data = table.concat(val, ", ")
+ else
+ data = val
+ end
+
+ end
+
+ if C:is_ngx_match_post(post_rules,data) then
C:write_log('post','regular')
C:return_html(config['post']['status'],post_html)
return true
@@ -366,10 +370,11 @@ function post_data_chekc()
end
if not list_list then return false end
- aaa=nil
+
+ aaa = nil
for k,v in pairs(request_args)
do
- aaa=v
+ aaa = v
end
if not aaa then return false end
@@ -381,7 +386,7 @@ function post_data_chekc()
if not data_len then return false end
if arrlen(data_len) ==0 then return false end
- if C:is_ngx_match(post_rules,data_len,'post') then
+ if C:is_ngx_match_post(post_rules , data_len) then
C:write_log('post','regular')
C:return_html(config['post']['status'],post_html)
return true
@@ -406,7 +411,7 @@ end
function post_X_Forwarded()
if not config['post']['open'] or not C:is_site_config('post') then return false end
if params['method'] ~= "POST" then return false end
- if C:is_ngx_match(post_rules,params["request_header"]['X-forwarded-For'],'post') then
+ if C:is_ngx_match_post(post_rules,params["request_header"]['X-forwarded-For']) then
C:write_log('post','regular')
C:return_html(config['post']['status'],post_html)
return true
@@ -415,39 +420,39 @@ function post_X_Forwarded()
end
-function php_path()
- if site_config[server_name] == nil then return false end
- for _,rule in ipairs(site_config[server_name]['disable_php_path'])
- do
- if ngx_match(uri,rule .. "/?.*\\.php$","isjo") then
- C:write_log('php_path','regular')
- C:return_html(config['other']['status'],other_html)
- return C:return_message(200,uri)
- end
- end
- return false
-end
-
-function url_path()
- if site_config[server_name] == nil then return false end
- for _,rule in ipairs(site_config[server_name]['disable_path'])
- do
- if ngx_match(uri,rule,"isjo") then
- C:write_log('path','regular')
- C:return_html(config['other']['status'],other_html)
- return true
- end
- end
- return false
-end
+-- function php_path()
+-- if site_config[server_name] == nil then return false end
+-- for _,rule in ipairs(site_config[server_name]['disable_php_path'])
+-- do
+-- if C:ngx_match_string(params['uri'],rule .. "/?.*\\.php$","isjo") then
+-- C:write_log('php_path','regular')
+-- C:return_html(config['other']['status'],other_html)
+-- return C:return_message(200,uri)
+-- end
+-- end
+-- return false
+-- end
+
+-- function url_path()
+-- if site_config[server_name] == nil then return false end
+-- for _,rule in ipairs(site_config[server_name]['disable_path'])
+-- do
+-- if ngx_match(uri,rule,"isjo") then
+-- C:write_log('path','regular')
+-- C:return_html(config['other']['status'],other_html)
+-- return true
+-- end
+-- end
+-- return false
+-- end
function url_ext()
if site_config[server_name] == nil then return false end
for _,rule in ipairs(site_config[server_name]['disable_ext'])
do
- if ngx_match(uri,"\\."..rule.."$","isjo") then
+ if C:ngx_match_string("\\."..rule.."$", params['uri'],'url_ext') then
C:write_log('url_ext','regular')
- C:return_html(config['other']['status'],other_html)
+ C:return_html(config['other']['status'], other_html)
return true
end
end
@@ -555,7 +560,7 @@ function waf_cookie()
if not params["request_header"]['cookie'] then return false end
if type(params["request_header"]['cookie']) ~= "string" then return false end
request_cookie = string.lower(params["request_header"]['cookie'])
- if C:is_ngx_match(cookie_rules,request_cookie,'cookie') then
+ if C:ngx_match_list(cookie_rules,request_cookie,'cookie') then
C:write_log('cookie','regular')
C:return_html(config['cookie']['status'],cookie_html)
return true
@@ -563,55 +568,45 @@ function waf_cookie()
return false
end
-function waf_referer()
- if params["method"] ~= "GET" then return false end
- if not config['get']['open'] or not C:is_site_config('get') then return false end
- if C:is_ngx_match(referer_local,params["request_header"]['Referer'],'args') then
- C:write_log('get_referer','regular')
- C:return_html(config['get']['status'], get_html)
- return true
- end
- return false
-end
function waf()
min_route()
+ -- white ip
if waf_ip_white() then return true end
- waf_ip_black()
+ -- black ip
+ if waf_ip_black() then return true end
- waf_drop()
- waf_user_agent()
- waf_url()
+ -- cc setting
+ if waf_drop() then return true end
+ if waf_cc() then return true end
- if params["method"] == "GET" then
- waf_referer()
- waf_cookie()
- end
+ -- ua check
+ if waf_user_agent() then return true end
+ if waf_url() then return true end
- if params["method"] == "POST" then
- waf_referer()
- waf_cookie()
- end
-
- waf_args()
- waf_scan_black()
+ -- cookie检查
+ if waf_cookie() then return true end
+
+ -- args参数拦截
+ if waf_get_args() then return true end
- waf_post()
- post_data_chekc()
+ -- 扫描软件禁止
+ if waf_scan_black() then return true end
- local server_name = params["server_name"]
- if site_config[server_name] then
- X_Forwarded()
- post_X_Forwarded()
- php_path()
- url_path()
- url_ext()
- url_rule_ex()
- url_tell()
- post_data()
+ if waf_post() then return true end
+ if post_data_chekc() then return true end
+
+ if site_config[server_name]['open'] then
+ if X_Forwarded() then return true end
+ if post_X_Forwarded() then return true end
+ -- url_path()
+ if url_ext() then return true end
+ -- url_rule_ex()
+ -- url_tell()
+ -- post_data()
end
end
diff --git a/plugins/op_waf/waf/rule/user_agent.json b/plugins/op_waf/waf/rule/user_agent.json
index b85a8e35d..0f5c5318c 100755
--- a/plugins/op_waf/waf/rule/user_agent.json
+++ b/plugins/op_waf/waf/rule/user_agent.json
@@ -1 +1 @@
-[[1, "(HTTrack|Apache-HttpClient|harvest|audit|dirbuster|pangolin|nmap|sqln|hydra|Parser|libwww|BBBike|sqlmap|w3af|owasp|Nikto|fimap|havij|zmeu|BabyKrokodil|netsparker|httperf| SF/)", "\u5173\u952e\u8bcd\u8fc7\u6ee41", 0]]
\ No newline at end of file
+[[1,"(HTTrack|Apache-HttpClient|harvest|audit|dirbuster|pangolin|nmap|sqln|hydra|Parser|libwww|BBBike|sqlmap|w3af|owasp|Nikto|fimap|havij|zmeu|BabyKrokodil|netsparker|httperf| SF/)","关键词过滤1",0],[1,"(ApacheBench)","AB测试",0]]
\ No newline at end of file
diff --git a/plugins/op_waf/waf/total.json b/plugins/op_waf/waf/total.json
index ca94ae3d3..4d111b7ed 100644
--- a/plugins/op_waf/waf/total.json
+++ b/plugins/op_waf/waf/total.json
@@ -1 +1 @@
-{"rules":{"user_agent":0,"cookie":0,"post":0,"args":0,"url":0,"cc":0},"sites":{},"total":0}
\ No newline at end of file
+{"rules":{"url_ext":0,"user_agent":0,"scan":0,"cookie":0,"post":0,"args":0,"url":0,"cc":0},"sites":{},"total":0}
\ No newline at end of file
diff --git a/plugins/php-apt/index.html b/plugins/php-apt/index.html
index 790f56c06..654c500c0 100755
--- a/plugins/php-apt/index.html
+++ b/plugins/php-apt/index.html
@@ -1,3 +1,41 @@
+
+
+
@@ -13,6 +51,7 @@
禁用函数
性能调整
负载状况
+
会话管理
FPM日志
慢日志
PHPIFNO
diff --git a/plugins/php-apt/index.py b/plugins/php-apt/index.py
index af7397d5e..f865e4ba9 100755
--- a/plugins/php-apt/index.py
+++ b/plugins/php-apt/index.py
@@ -490,6 +490,180 @@ def getFpmStatus(version):
return mw.returnJson(True, "OK", data)
+def getSessionConf(version):
+ filename = getConf(version)
+ if not os.path.exists(filename):
+ return mw.returnJson(False, '指定PHP版本不存在!')
+
+ phpini = mw.readFile(filename)
+
+ rep = r'session.save_handler\s*=\s*([0-9A-Za-z_& ~]+)(\s*;?|\r?\n)'
+ save_handler = re.search(rep, phpini)
+ if save_handler:
+ save_handler = save_handler.group(1)
+ else:
+ save_handler = "files"
+
+ reppath = r'\nsession.save_path\s*=\s*"tcp\:\/\/([\d\.]+):(\d+).*\r?\n'
+ passrep = r'\nsession.save_path\s*=\s*"tcp://[\w\.\?\:]+=(.*)"\r?\n'
+ memcached = r'\nsession.save_path\s*=\s*"([\d\.]+):(\d+)"'
+ save_path = re.search(reppath, phpini)
+ if not save_path:
+ save_path = re.search(memcached, phpini)
+ passwd = re.search(passrep, phpini)
+ port = ""
+ if passwd:
+ passwd = passwd.group(1)
+ else:
+ passwd = ""
+ if save_path:
+ port = save_path.group(2)
+ save_path = save_path.group(1)
+
+ else:
+ save_path = ""
+
+ data = {"save_handler": save_handler, "save_path": save_path,
+ "passwd": passwd, "port": port}
+ return mw.returnJson(True, 'ok', data)
+
+
+def setSessionConf(version):
+
+ args = getArgs()
+
+ ip = args['ip']
+ port = args['port']
+ passwd = args['passwd']
+ save_handler = args['save_handler']
+
+ if save_handler != "file":
+ iprep = r"(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})"
+ if not re.search(iprep, ip):
+ return mw.returnJson(False, '请输入正确的IP地址')
+
+ try:
+ port = int(port)
+ if port >= 65535 or port < 1:
+ return mw.returnJson(False, '请输入正确的端口号')
+ except:
+ return mw.returnJson(False, '请输入正确的端口号')
+ prep = r"[\~\`\/\=]"
+ if re.search(prep, passwd):
+ return mw.returnJson(False, '请不要输入以下特殊字符 " ~ ` / = "')
+
+ filename = getConf(version)
+ if not os.path.exists(filename):
+ return mw.returnJson(False, '指定PHP版本不存在!')
+ phpini = mw.readFile(filename)
+
+ session_tmp = getServerDir() + "/tmp/session"
+
+ rep = r'session.save_handler\s*=\s*(.+)\r?\n'
+ val = r'session.save_handler = ' + save_handler + '\n'
+ phpini = re.sub(rep, val, phpini)
+
+ content = mw.execShell(
+ 'cat /etc/php/' + version + '/fpm/conf.d/*' + " | grep -v '^;' |tr -s '\n'")
+ content = content[0]
+
+ if save_handler == "memcached":
+ if not re.search("memcached.so", phpini):
+ return mw.returnJson(False, '请先安装%s扩展' % save_handler)
+ rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
+ val = r'\nsession.save_path = "%s:%s" \n' % (ip, port)
+ if re.search(rep, phpini):
+ phpini = re.sub(rep, val, phpini)
+ else:
+ phpini = re.sub('\n;session.save_path = "' + "/var/lib/php/sessions" + '"',
+ '\n;session.save_path = "' + "/var/lib/php/sessions" + '"' + val, phpini)
+
+ if save_handler == "memcache":
+ if not content.find('memcache') > -1:
+ return mw.returnJson(False, '请先安装%s扩展' % save_handler)
+ rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
+ val = r'\nsession.save_path = "%s:%s" \n' % (ip, port)
+ if re.search(rep, phpini):
+ phpini = re.sub(rep, val, phpini)
+ else:
+ phpini = re.sub('\n;session.save_path = "' + "/var/lib/php/sessions" + '"',
+ '\n;session.save_path = "' + "/var/lib/php/sessions" + '"' + val, phpini)
+
+ if save_handler == "redis":
+ if not content.find('redis') > -1:
+ return mw.returnJson(False, '请先安装%s扩展' % save_handler)
+ if passwd:
+ passwd = "?auth=" + passwd
+ else:
+ passwd = ""
+ rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
+ val = r'\nsession.save_path = "tcp://%s:%s%s"\n' % (ip, port, passwd)
+ res = re.search(rep, phpini)
+ if res:
+ phpini = re.sub(rep, val, phpini)
+ else:
+ phpini = re.sub('\n;session.save_path = "' + "/var/lib/php/sessions" + '"',
+ '\n;session.save_path = "' + "/var/lib/php/sessions" + '"' + val, phpini)
+
+ if save_handler == "file":
+ rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
+ val = r'\nsession.save_path = "' + session_tmp + '"\n'
+ if re.search(rep, phpini):
+ phpini = re.sub(rep, val, phpini)
+ else:
+ phpini = re.sub('\n;session.save_path = "' + "/var/lib/php/sessions" + '"',
+ '\n;session.save_path = "' + "/var/lib/php/sessions" + '"' + val, phpini)
+
+ mw.writeFile(filename, phpini)
+ reload(version)
+ return mw.returnJson(True, '设置成功!')
+
+
+def getSessionCount_Origin(version):
+ session_tmp = getServerDir() + "/tmp/session"
+ d = ["/tmp", "/var/lib/php/sessions", session_tmp]
+ count = 0
+ for i in d:
+ if not os.path.exists(i):
+ mw.execShell('mkdir -p %s' % i)
+ list = os.listdir(i)
+ for l in list:
+ if os.path.isdir(i + "/" + l):
+ l1 = os.listdir(i + "/" + l)
+ for ll in l1:
+ if "sess_" in ll:
+ count += 1
+ continue
+ if "sess_" in l:
+ count += 1
+
+ s = "find /tmp -mtime +1 |grep 'sess_' | wc -l"
+ old_file = int(mw.execShell(s)[0].split("\n")[0])
+
+ s = "find " + session_tmp + " -mtime +1 |grep 'sess_'|wc -l"
+ old_file += int(mw.execShell(s)[0].split("\n")[0])
+ return {"total": count, "oldfile": old_file}
+
+
+def getSessionCount(version):
+ data = getSessionCount_Origin(version)
+ return mw.returnJson(True, 'ok!', data)
+
+
+def cleanSessionOld(version):
+ s = "find /tmp -mtime +1 |grep 'sess_'|xargs rm -f"
+ mw.execShell(s)
+
+ session_tmp = getServerDir() + "/tmp/session"
+ s = "find " + session_tmp + " -mtime +1 |grep 'sess_' |xargs rm -f"
+ mw.execShell(s)
+ old_file_conf = getSessionCount_Origin(version)["oldfile"]
+ if old_file_conf == 0:
+ return mw.returnJson(True, '清理成功')
+ else:
+ return mw.returnJson(True, '清理失败')
+
+
def getDisableFunc(version):
filename = getConf(version)
if not os.path.exists(filename):
@@ -688,6 +862,14 @@ if __name__ == "__main__":
print(setFpmConfig(version))
elif func == 'get_fpm_status':
print(getFpmStatus(version))
+ elif func == 'get_session_conf':
+ print(getSessionConf(version))
+ elif func == 'set_session_conf':
+ print(setSessionConf(version))
+ elif func == 'get_session_count':
+ print(getSessionCount(version))
+ elif func == 'clean_session_old':
+ print(cleanSessionOld(version))
elif func == 'get_disable_func':
print(getDisableFunc(version))
elif func == 'set_disable_func':
diff --git a/plugins/php-apt/js/php.js b/plugins/php-apt/js/php.js
index fd6e14003..9b20f6f98 100755
--- a/plugins/php-apt/js/php.js
+++ b/plugins/php-apt/js/php.js
@@ -368,6 +368,151 @@ function disableFunc(version) {
$(".soft-man-con").html(con);
});
}
+
+
+
+function getSessionConfig(version){
+ phpPost('get_session_conf', version, '', function(ret_data){
+ var rdata = $.parseJSON(ret_data.data);
+ if(!rdata.status){
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
+ return;
+ }
+ var rdata = rdata.data;
+
+ var cacheList = "
" +
+ "
" +
+ "
" +
+ "
";
+
+
+ var info = rdata.save_path.split(":");
+ var con = "
" +
+ "
存储模式:
" +
+ "
IP地址:
" +
+ "
端口:
" +
+ "
密码:
" +
+ "
" +
+ "
\
+
\
+ - 若你的站点并发比较高,使用Redis,Memcache能有效提升PHP并发能力
\
+ - 若调整Session模式后,网站访问异常,请切换回原来的模式
\
+ - 切换Session模式会使在线的用户会话丢失,请在流量小的时候切换
\
+
\
+
\
+
\
+
";
+
+ $(".soft-man-con").html(con);
+
+ if (rdata.save_handler == 'file'){
+ $('input[name="ip"]').attr('disabled','disabled');
+ $('input[name="port"]').attr('disabled','disabled');
+ $('input[name="passwd"]').attr('placeholder','如果没有密码留空');
+ $('input[name="passwd"]').attr('disabled','disabled');
+ }
+
+ // change event
+ $("select[name='save_handler']").change(function() {
+ var type = $(this).val();
+
+ var passwd = $('input[name="passwd"]').val();
+ if (passwd == ""){
+ $('input[name="passwd"]').attr('placeholder','如果没有密码留空');
+ }
+
+ var ip = $('input[name="ip"]').val();
+ if (ip == ""){
+ $('input[name="ip"]').val('127.0.0.1');
+ }
+
+ switch (type) {
+ case 'redis':
+ var port = $('input[name="port"]').val();
+ if (port == ""){
+ $('input[name="port"]').val('6379');
+ }
+ $('input[name="ip"]').removeAttr('disabled');
+ $('input[name="port"]').removeAttr('disabled');
+ $('input[name="passwd"]').removeAttr('disabled');
+ break;
+ case 'file':
+ $('input[name="ip"]').val("").attr('disabled','disabled');
+ $('input[name="port"]').val("").attr('disabled','disabled');
+ $('input[name="passwd"]').val("").attr('disabled','disabled');
+ break;
+ case 'memcache':
+ var port = $('input[name="port"]').val();
+ if (port == ""){
+ $('input[name="port"]').val('11211');
+ }
+ $('input[name="ip"]').removeAttr('disabled');
+ $('input[name="port"]').removeAttr('disabled');
+ $('input[name="passwd"]').removeAttr('disabled');
+ break;
+ case 'memcached':
+ var port = $('input[name="port"]').val();
+ if (port == ""){
+ $('input[name="port"]').val('11211');
+ }
+ $('input[name="ip"]').removeAttr('disabled');
+ $('input[name="port"]').removeAttr('disabled');
+ $('input[name="passwd"]').removeAttr('disabled');
+ break;
+ }
+ });
+
+ //load session stats
+ phpPost('get_session_count', version, '', function(ret_data){
+ var rdata = $.parseJSON(ret_data.data);
+ if(!rdata.status){
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
+ return;
+ }
+ var rdata = rdata.data;
+
+ var html_var = "
清理Session文件
\
+
\
+
\
+
总Session文件数量"+rdata.total+"
\
+
可清理的Session文件数量"+rdata.oldfile+"
\
+
\
+
";
+
+ $("#session_clear").html(html_var);
+
+
+ $('#clean_func').click(function(){
+ phpPost('clean_session_old', version, '', function(ret_data){
+ var rdata = $.parseJSON(ret_data.data);
+ showMsg(rdata.msg,function(){
+ getSessionConfig(version);
+ },{ icon: rdata.status ? 1 : 2 });
+ });
+ });
+ });
+ });
+
+}
+
+function setSessionConfig(version){
+ var ip = $('input[name="ip"]').val();
+ var port = $('input[name="port"]').val();
+ var passwd = $('input[name="passwd"]').val();
+ var save_handler = $("select[name='save_handler']").val();
+ var data = {
+ ip:ip,
+ port:port,
+ passwd:passwd,
+ save_handler:save_handler,
+ };
+ phpPost('set_session_conf', version, data, function(ret_data){
+ var rdata = $.parseJSON(ret_data.data);
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
+ });
+}
+
+
//设置禁用函数
function setDisableFunc(version, act, fs) {
var fsArr = fs.split(',');
diff --git a/plugins/php-yum/index.html b/plugins/php-yum/index.html
index 3b4957222..878e98f41 100755
--- a/plugins/php-yum/index.html
+++ b/plugins/php-yum/index.html
@@ -1,3 +1,40 @@
+
+
@@ -13,6 +50,7 @@
禁用函数
性能调整
负载状况
+
会话管理
FPM日志
慢日志
PHPIFNO
diff --git a/plugins/php-yum/index.py b/plugins/php-yum/index.py
index e99c25867..a6595ab89 100755
--- a/plugins/php-yum/index.py
+++ b/plugins/php-yum/index.py
@@ -492,6 +492,180 @@ def getFpmStatus(version):
return mw.returnJson(True, "OK", data)
+def getSessionConf(version):
+ filename = getConf(version)
+ if not os.path.exists(filename):
+ return mw.returnJson(False, '指定PHP版本不存在!')
+
+ phpini = mw.readFile(filename)
+
+ rep = r'session.save_handler\s*=\s*([0-9A-Za-z_& ~]+)(\s*;?|\r?\n)'
+ save_handler = re.search(rep, phpini)
+ if save_handler:
+ save_handler = save_handler.group(1)
+ else:
+ save_handler = "files"
+
+ reppath = r'\nsession.save_path\s*=\s*"tcp\:\/\/([\d\.]+):(\d+).*\r?\n'
+ passrep = r'\nsession.save_path\s*=\s*"tcp://[\w\.\?\:]+=(.*)"\r?\n'
+ memcached = r'\nsession.save_path\s*=\s*"([\d\.]+):(\d+)"'
+ save_path = re.search(reppath, phpini)
+ if not save_path:
+ save_path = re.search(memcached, phpini)
+ passwd = re.search(passrep, phpini)
+ port = ""
+ if passwd:
+ passwd = passwd.group(1)
+ else:
+ passwd = ""
+ if save_path:
+ port = save_path.group(2)
+ save_path = save_path.group(1)
+
+ else:
+ save_path = ""
+
+ data = {"save_handler": save_handler, "save_path": save_path,
+ "passwd": passwd, "port": port}
+ return mw.returnJson(True, 'ok', data)
+
+
+def setSessionConf(version):
+
+ args = getArgs()
+
+ ip = args['ip']
+ port = args['port']
+ passwd = args['passwd']
+ save_handler = args['save_handler']
+
+ if save_handler != "file":
+ iprep = r"(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})"
+ if not re.search(iprep, ip):
+ return mw.returnJson(False, '请输入正确的IP地址')
+
+ try:
+ port = int(port)
+ if port >= 65535 or port < 1:
+ return mw.returnJson(False, '请输入正确的端口号')
+ except:
+ return mw.returnJson(False, '请输入正确的端口号')
+ prep = r"[\~\`\/\=]"
+ if re.search(prep, passwd):
+ return mw.returnJson(False, '请不要输入以下特殊字符 " ~ ` / = "')
+
+ filename = getConf(version)
+ if not os.path.exists(filename):
+ return mw.returnJson(False, '指定PHP版本不存在!')
+ phpini = mw.readFile(filename)
+
+ session_tmp = getServerDir() + "/tmp/session"
+
+ rep = r'session.save_handler\s*=\s*(.+)\r?\n'
+ val = r'session.save_handler = ' + save_handler + '\n'
+ phpini = re.sub(rep, val, phpini)
+
+ content = mw.execShell('cat /etc/opt/remi/php' +
+ version + "/php.d/* | grep -v '^;' |tr -s '\n'")
+ content = content[0]
+
+ if save_handler == "memcached":
+ if not content.find("memcached.so") > -1:
+ return mw.returnJson(False, '请先安装%s扩展' % save_handler)
+ rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
+ val = r'\nsession.save_path = "%s:%s" \n' % (ip, port)
+ if re.search(rep, phpini):
+ phpini = re.sub(rep, val, phpini)
+ else:
+ phpini = re.sub('\n;session.save_path = "/tmp"',
+ '\n;session.save_path = "/tmp"' + val, phpini)
+
+ if save_handler == "memcache":
+ if not content.find("memcache.so") > -1:
+ return mw.returnJson(False, '请先安装%s扩展' % save_handler)
+ rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
+ val = r'\nsession.save_path = "%s:%s" \n' % (ip, port)
+ if re.search(rep, phpini):
+ phpini = re.sub(rep, val, phpini)
+ else:
+ phpini = re.sub('\n;session.save_path = "/tmp"',
+ '\n;session.save_path = "/tmp"' + val, phpini)
+
+ if save_handler == "redis":
+ if not content.find("redis.so") > -1:
+ return mw.returnJson(False, '请先安装%s扩展' % save_handler)
+ if passwd:
+ passwd = "?auth=" + passwd
+ else:
+ passwd = ""
+ rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
+ val = r'\nsession.save_path = "tcp://%s:%s%s"\n' % (ip, port, passwd)
+ res = re.search(rep, phpini)
+ if res:
+ phpini = re.sub(rep, val, phpini)
+ else:
+ phpini = re.sub('\n;session.save_path = "/tmp"',
+ '\n;session.save_path = "/tmp"' + val, phpini)
+
+ if save_handler == "file":
+ rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
+ val = r'\nsession.save_path = "' + session_tmp + '"\n'
+ if re.search(rep, phpini):
+ phpini = re.sub(rep, val, phpini)
+ else:
+ phpini = re.sub('\n;session.save_path = "/tmp"',
+ '\n;session.save_path = "/tmp"' + val, phpini)
+
+ mw.writeFile(filename, phpini)
+ restart(version)
+ return mw.returnJson(True, '设置成功!')
+
+
+def getSessionCount_Origin(version):
+ session_tmp = getServerDir() + "/tmp/session"
+ d = ["/tmp", session_tmp]
+ count = 0
+ for i in d:
+ if not os.path.exists(i):
+ mw.execShell('mkdir -p %s' % i)
+ list = os.listdir(i)
+ for l in list:
+ if os.path.isdir(i + "/" + l):
+ l1 = os.listdir(i + "/" + l)
+ for ll in l1:
+ if "sess_" in ll:
+ count += 1
+ continue
+ if "sess_" in l:
+ count += 1
+
+ s = "find /tmp -mtime +1 |grep 'sess_' | wc -l"
+ old_file = int(mw.execShell(s)[0].split("\n")[0])
+
+ s = "find " + session_tmp + " -mtime +1 |grep 'sess_'|wc -l"
+ old_file += int(mw.execShell(s)[0].split("\n")[0])
+ return {"total": count, "oldfile": old_file}
+
+
+def getSessionCount(version):
+ data = getSessionCount_Origin(version)
+ return mw.returnJson(True, 'ok!', data)
+
+
+def cleanSessionOld(version):
+ s = "find /tmp -mtime +1 |grep 'sess_'|xargs rm -f"
+ mw.execShell(s)
+
+ session_tmp = getServerDir() + "/tmp/session"
+ s = "find " + session_tmp + " -mtime +1 |grep 'sess_' |xargs rm -f"
+ mw.execShell(s)
+ old_file_conf = getSessionCount_Origin(version)["oldfile"]
+ if old_file_conf == 0:
+ return mw.returnJson(True, '清理成功')
+ else:
+ return mw.returnJson(True, '清理失败')
+
+
def getDisableFunc(version):
filename = getConf(version)
if not os.path.exists(filename):
@@ -689,6 +863,14 @@ if __name__ == "__main__":
print(setFpmConfig(version))
elif func == 'get_fpm_status':
print(getFpmStatus(version))
+ elif func == 'get_session_conf':
+ print(getSessionConf(version))
+ elif func == 'set_session_conf':
+ print(setSessionConf(version))
+ elif func == 'get_session_count':
+ print(getSessionCount(version))
+ elif func == 'clean_session_old':
+ print(cleanSessionOld(version))
elif func == 'get_disable_func':
print(getDisableFunc(version))
elif func == 'set_disable_func':
diff --git a/plugins/php-yum/js/php.js b/plugins/php-yum/js/php.js
index e059e3a36..332158bbd 100755
--- a/plugins/php-yum/js/php.js
+++ b/plugins/php-yum/js/php.js
@@ -340,6 +340,147 @@ function getFpmStatus(version){
});
}
+function getSessionConfig(version){
+ phpPost('get_session_conf', version, '', function(ret_data){
+ var rdata = $.parseJSON(ret_data.data);
+ if(!rdata.status){
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
+ return;
+ }
+ var rdata = rdata.data;
+
+ var cacheList = "
" +
+ "
" +
+ "
" +
+ "
";
+
+
+ var info = rdata.save_path.split(":");
+ var con = "
" +
+ "
存储模式:
" +
+ "
IP地址:
" +
+ "
端口:
" +
+ "
密码:
" +
+ "
" +
+ "
\
+
\
+ - 若你的站点并发比较高,使用Redis,Memcache能有效提升PHP并发能力
\
+ - 若调整Session模式后,网站访问异常,请切换回原来的模式
\
+ - 切换Session模式会使在线的用户会话丢失,请在流量小的时候切换
\
+
\
+
\
+
\
+
";
+
+ $(".soft-man-con").html(con);
+
+ if (rdata.save_handler == 'file'){
+ $('input[name="ip"]').attr('disabled','disabled');
+ $('input[name="port"]').attr('disabled','disabled');
+ $('input[name="passwd"]').attr('placeholder','如果没有密码留空');
+ $('input[name="passwd"]').attr('disabled','disabled');
+ }
+
+ // change event
+ $("select[name='save_handler']").change(function() {
+ var type = $(this).val();
+
+ var passwd = $('input[name="passwd"]').val();
+ if (passwd == ""){
+ $('input[name="passwd"]').attr('placeholder','如果没有密码留空');
+ }
+
+ var ip = $('input[name="ip"]').val();
+ if (ip == ""){
+ $('input[name="ip"]').val('127.0.0.1');
+ }
+
+ switch (type) {
+ case 'redis':
+ var port = $('input[name="port"]').val();
+ if (port == ""){
+ $('input[name="port"]').val('6379');
+ }
+ $('input[name="ip"]').removeAttr('disabled');
+ $('input[name="port"]').removeAttr('disabled');
+ $('input[name="passwd"]').removeAttr('disabled');
+ break;
+ case 'file':
+ $('input[name="ip"]').val("").attr('disabled','disabled');
+ $('input[name="port"]').val("").attr('disabled','disabled');
+ $('input[name="passwd"]').val("").attr('disabled','disabled');
+ break;
+ case 'memcache':
+ var port = $('input[name="port"]').val();
+ if (port == ""){
+ $('input[name="port"]').val('11211');
+ }
+ $('input[name="ip"]').removeAttr('disabled');
+ $('input[name="port"]').removeAttr('disabled');
+ $('input[name="passwd"]').removeAttr('disabled');
+ break;
+ case 'memcached':
+ var port = $('input[name="port"]').val();
+ if (port == ""){
+ $('input[name="port"]').val('11211');
+ }
+ $('input[name="ip"]').removeAttr('disabled');
+ $('input[name="port"]').removeAttr('disabled');
+ $('input[name="passwd"]').removeAttr('disabled');
+ break;
+ }
+ });
+
+ //load session stats
+ phpPost('get_session_count', version, '', function(ret_data){
+ var rdata = $.parseJSON(ret_data.data);
+ if(!rdata.status){
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
+ return;
+ }
+ var rdata = rdata.data;
+
+ var html_var = "
清理Session文件
\
+
\
+
\
+
总Session文件数量"+rdata.total+"
\
+
可清理的Session文件数量"+rdata.oldfile+"
\
+
\
+
";
+
+ $("#session_clear").html(html_var);
+
+
+ $('#clean_func').click(function(){
+ phpPost('clean_session_old', version, '', function(ret_data){
+ var rdata = $.parseJSON(ret_data.data);
+ showMsg(rdata.msg,function(){
+ getSessionConfig(version);
+ },{ icon: rdata.status ? 1 : 2 });
+ });
+ });
+ });
+ });
+
+}
+
+function setSessionConfig(version){
+ var ip = $('input[name="ip"]').val();
+ var port = $('input[name="port"]').val();
+ var passwd = $('input[name="passwd"]').val();
+ var save_handler = $("select[name='save_handler']").val();
+ var data = {
+ ip:ip,
+ port:port,
+ passwd:passwd,
+ save_handler:save_handler,
+ };
+ phpPost('set_session_conf', version, data, function(ret_data){
+ var rdata = $.parseJSON(ret_data.data);
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
+ });
+}
+
//禁用函数
function disableFunc(version) {
phpPost('get_disable_func', version,'',function(data){
diff --git a/plugins/php/index.html b/plugins/php/index.html
index 05dd0c4ac..5ec54976c 100755
--- a/plugins/php/index.html
+++ b/plugins/php/index.html
@@ -1,6 +1,43 @@
+
+