diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..4dca92b
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..3b31283
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..9e6e353
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..22f51ac
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/ngx_lua_waf.iml b/.idea/ngx_lua_waf.iml
new file mode 100644
index 0000000..6711606
--- /dev/null
+++ b/.idea/ngx_lua_waf.iml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..7d4efb8
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ DEFINITION_ORDER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1474616676553
+
+
+ 1474616676553
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config.lua b/config.lua
index 67d330c..ee3056b 100644
--- a/config.lua
+++ b/config.lua
@@ -1,23 +1,26 @@
-debug = false
--- rule_path = "/data/server/nginx/conf/waf/wafconf/"
--- url_check = false
--- url_write_check = false
--- args_check = false
--- ua_check = false
--- ua_write_check = false
--- cookie_check = false
--- post_check = false
+--
+-- Created by IntelliJ IDEA.
+-- User: guang
+-- Date: 16/9/23
+-- Time: 下午4:28
+-- To change this template use File | Settings | File Templates.
+--
--- black_file_ext = {"php", "jsp"}
--- attack_log = false
--- attach_log_dir = "/data/logs/waf/"
+local _M = {}
+_M.version = '0.1.0'
--- redirect = false
--- redirect_url = "http://www.baidu.com"
-ip_check = false
-ip_white_list = {} -- {'192.168.1.*', '127.0.0.1'}
-ip_black_list = {} -- {'0.0.0.0', '106.2.34.29'}
-cc_deny = false
-cc_rate = "100/60"
-cc_deny_seconds = "600"
+_M.defaults = {
+ debug = true,
+ active = false,
+ cc_deny = true,
+ cc_rate = "100/600",
+ cc_deny_seconds = 600,
+ cc_deny_code = 404,
+ log_path = "/tmp/nginx_waf.log",
+ ip_check= true,
+ ip_white_list = nil,
+ ip_black_list = nil,
+}
+
+return _M
diff --git a/core.lua b/core.lua
new file mode 100644
index 0000000..590992d
--- /dev/null
+++ b/core.lua
@@ -0,0 +1,95 @@
+--
+-- Created by IntelliJ IDEA.
+-- User: guang
+-- Date: 16/9/22
+-- Time: 下午7:13
+-- To change this template use File | Settings | File Templates.
+--
+
+
+local _M = {}
+_M.version = '0.1.0'
+log_inited = {}
+
+local get_headers = ngx.req.get_headers
+local config = require "config"
+local mt = {__index=_M }
+
+local function get_client_ip()
+ local ip = get_headers()["X-Real-IP"]
+ if ip == nil then
+ ip = ngx.var.remote_addr
+ end
+
+ if ip == nil then
+ ip = "unkown"
+ end
+ return ip
+end
+
+function _M.table_copy(orig_table)
+ local copy = {}
+
+ for k, v in pairs(orig_table) do
+ if type(v) ~= "table" then
+ copy[k] = v
+ else
+ copy[k] = _M.table_copy(v)
+ end
+ end
+ return copy
+end
+
+function _M.new(self, name)
+ local t = {}
+ t["name"] = name
+ t["config"] = _M.table_copy(config.defaults)
+ return setmetatable(t, mt)
+end
+
+function _M.set_option(self, key, value)
+ self["config"][key] = value
+end
+
+function _M.deny_cc(self)
+ local uri = ngx.var.uri
+ local max_visit = tonumber(string.match(self.config.cc_rate, '(.*)/'))
+ local count_period = tonumber(string.match(self.config.cc_rate, '/(.*)'))
+ local ip = get_client_ip()
+
+ local token = ip..":"..uri
+ local limit = ngx.shared.limit
+ local req, _ = limit:get(token)
+
+ if req then
+ if req > max_visit then
+ ngx.exit(self.config.cc_deny_code)
+ return true
+ elseif req == max_visit then
+ self:log("[Block] " .. token)
+ limit:incr(token, 1)
+ else
+ limit:incr(token, 1)
+ end
+ else
+ limit:set(token, 1, count_period)
+ end
+end
+
+function _M.log(self, msg)
+ if log_inited[self.config.log_path] == nil then
+ log_inited[self.config.log_path] = io.open(self.config.log_path, 'ab')
+ end
+ self.fd = log_inited[self.config.log_path]
+
+ self.fd:write(msg .. '\n')
+ self.fd:flush()
+end
+
+function _M.run(self)
+ ngx.log(ngx.WARN, 'Start running waf')
+ if self.config.cc_deny and self:deny_cc() then
+ end
+end
+
+return _M
diff --git a/iputils.lua b/iputils.lua
new file mode 100644
index 0000000..e5d1dd2
--- /dev/null
+++ b/iputils.lua
@@ -0,0 +1,207 @@
+local ipairs, tonumber, tostring, type = ipairs, tonumber, tostring, type
+local bit = require("bit")
+local tobit = bit.tobit
+local lshift = bit.lshift
+local band = bit.band
+local bor = bit.bor
+local xor = bit.bxor
+local byte = string.byte
+local str_find = string.find
+local str_sub = string.sub
+
+local lrucache = nil
+
+local _M = {
+ _VERSION = '0.02',
+}
+
+local mt = { __index = _M }
+
+
+-- Precompute binary subnet masks...
+local bin_masks = {}
+for i=1,32 do
+ bin_masks[tostring(i)] = lshift(tobit((2^i)-1), 32-i)
+end
+-- ... and their inverted counterparts
+local bin_inverted_masks = {}
+for i=1,32 do
+ local i = tostring(i)
+ bin_inverted_masks[i] = xor(bin_masks[i], bin_masks["32"])
+end
+
+local log_err
+if ngx then
+ log_err = function(...)
+ ngx.log(ngx.ERR, ...)
+ end
+else
+ log_err = function(...)
+ print(...)
+ end
+end
+
+
+local function enable_lrucache(size)
+ local size = size or 4000 -- Cache the last 4000 IPs (~1MB memory) by default
+ local lrucache_obj, err = require("resty.lrucache").new(4000)
+ if not lrucache_obj then
+ return nil, "failed to create the cache: " .. (err or "unknown")
+ end
+ lrucache = lrucache_obj
+ return true
+end
+_M.enable_lrucache = enable_lrucache
+
+
+local function split_octets(input)
+ local pos = 0
+ local prev = 0
+ local octs = {}
+
+ for i=1, 4 do
+ pos = str_find(input, ".", prev, true)
+ if pos then
+ if i == 4 then
+ -- Should not have a match after 4 octets
+ return nil, "Invalid IP"
+ end
+ octs[i] = str_sub(input, prev, pos-1)
+ elseif i == 4 then
+ -- Last octet, get everything to the end
+ octs[i] = str_sub(input, prev, -1)
+ break
+ else
+ return nil, "Invalid IP"
+ end
+ prev = pos +1
+ end
+
+ return octs
+end
+
+
+local function ip2bin(ip)
+ if lrucache then
+ local get = lrucache:get(ip)
+ if get then
+ return get[1], get[2]
+ end
+ end
+
+ if type(ip) ~= "string" then
+ return nil, "IP must be a string"
+ end
+
+ local octets = split_octets(ip)
+ if not octets or #octets ~= 4 then
+ return nil, "Invalid IP"
+ end
+
+ -- Return the binary representation of an IP and a table of binary octets
+ local bin_octets = {}
+ local bin_ip = 0
+
+ for i,octet in ipairs(octets) do
+ local bin_octet = tonumber(octet)
+ if not bin_octet or bin_octet > 255 then
+ return nil, "Invalid octet: "..tostring(octet)
+ end
+ bin_octet = tobit(bin_octet)
+ bin_octets[i] = bin_octet
+ bin_ip = bor(lshift(bin_octet, 8*(4-i) ), bin_ip)
+ end
+
+ if lrucache then
+ lrucache:set(ip, {bin_ip, bin_octets})
+ end
+ return bin_ip, bin_octets
+end
+_M.ip2bin = ip2bin
+
+
+local function split_cidr(input)
+ local pos = str_find(input, "/", 0, true)
+ if not pos then
+ return {input}
+ end
+ return {str_sub(input, 1, pos-1), str_sub(input, pos+1, -1)}
+end
+
+
+local function parse_cidr(cidr)
+ local mask_split = split_cidr(cidr, '/')
+ local net = mask_split[1]
+ local mask = mask_split[2] or "32"
+ local mask_num = tonumber(mask)
+ if not mask_num or (mask_num > 32 or mask_num < 1) then
+ return nil, "Invalid prefix: /"..tostring(mask)
+ end
+
+ local bin_net, err = ip2bin(net) -- Convert IP to binary
+ if not bin_net then
+ return nil, err
+ end
+ local bin_mask = bin_masks[mask] -- Get masks
+ local bin_inv_mask = bin_inverted_masks[mask]
+
+ local lower = band(bin_net, bin_mask) -- Network address
+ local upper = bor(lower, bin_inv_mask) -- Broadcast address
+ return lower, upper
+end
+_M.parse_cidr = parse_cidr
+
+
+local function parse_cidrs(cidrs)
+ local out = {}
+ local i = 1
+ for _,cidr in ipairs(cidrs) do
+ local lower, upper = parse_cidr(cidr)
+ if not lower then
+ log_err("Error parsing '", cidr, "': ", upper)
+ else
+ out[i] = {lower, upper}
+ i = i+1
+ end
+ end
+ return out
+end
+_M.parse_cidrs = parse_cidrs
+
+
+local function ip_in_cidrs(ip, cidrs)
+ local bin_ip, bin_octets = ip2bin(ip)
+ if not bin_ip then
+ return nil, bin_octets
+ end
+
+ for _,cidr in ipairs(cidrs) do
+ if bin_ip >= cidr[1] and bin_ip <= cidr[2] then
+ return true
+ end
+ end
+ return false
+end
+_M.ip_in_cidrs = ip_in_cidrs
+
+
+local function binip_in_cidrs(bin_ip_ngx, cidrs)
+ if 4 ~= #bin_ip_ngx then
+ return false, "invalid IP address"
+ end
+
+ local bin_ip = 0
+ for i=1,4 do
+ bin_ip = bor(lshift(bin_ip, 8), tobit(byte(bin_ip_ngx, i)))
+ end
+
+ for _,cidr in ipairs(cidrs) do
+ if bin_ip >= cidr[1] and bin_ip <= cidr[2] then
+ return true
+ end
+ end
+ return false
+end
+_M.binip_in_cidrs = binip_in_cidrs
+
+return _M
diff --git a/README.md b/old/README.md
similarity index 100%
rename from README.md
rename to old/README.md
diff --git a/old/config.lua b/old/config.lua
new file mode 100644
index 0000000..67d330c
--- /dev/null
+++ b/old/config.lua
@@ -0,0 +1,23 @@
+debug = false
+-- rule_path = "/data/server/nginx/conf/waf/wafconf/"
+-- url_check = false
+-- url_write_check = false
+-- args_check = false
+-- ua_check = false
+-- ua_write_check = false
+-- cookie_check = false
+-- post_check = false
+
+-- black_file_ext = {"php", "jsp"}
+-- attack_log = false
+-- attach_log_dir = "/data/logs/waf/"
+
+-- redirect = false
+-- redirect_url = "http://www.baidu.com"
+ip_check = false
+ip_white_list = {} -- {'192.168.1.*', '127.0.0.1'}
+ip_black_list = {} -- {'0.0.0.0', '106.2.34.29'}
+
+cc_deny = false
+cc_rate = "100/60"
+cc_deny_seconds = "600"
diff --git a/entry.lua b/old/entry.lua
similarity index 88%
rename from entry.lua
rename to old/entry.lua
index f4aaa4b..7bcea95 100644
--- a/entry.lua
+++ b/old/entry.lua
@@ -9,8 +9,6 @@ ip_check = true
ip_white_list = {}
ip_black_list = {}
---------- Init project ----------------
-require 'init'
--------- Access control limit --------
if ip_check and (whiteIP(ip_white_list, debug) or blackIP(ip_black_list, debug)) then
elseif cc_deny and denyCC(cc_rate, cc_deny_seconds, debug) then
diff --git a/init.lua b/old/init.lua
similarity index 100%
rename from init.lua
rename to old/init.lua
diff --git a/old/logger.lua b/old/logger.lua
new file mode 100644
index 0000000..e69de29
diff --git a/old/waf.lua b/old/waf.lua
new file mode 100644
index 0000000..e69de29
diff --git a/wafconf/args b/old/wafconf/args
similarity index 100%
rename from wafconf/args
rename to old/wafconf/args
diff --git a/wafconf/cookie b/old/wafconf/cookie
similarity index 100%
rename from wafconf/cookie
rename to old/wafconf/cookie
diff --git a/wafconf/post b/old/wafconf/post
similarity index 100%
rename from wafconf/post
rename to old/wafconf/post
diff --git a/wafconf/url b/old/wafconf/url
similarity index 100%
rename from wafconf/url
rename to old/wafconf/url
diff --git a/wafconf/user_agent b/old/wafconf/user_agent
similarity index 100%
rename from wafconf/user_agent
rename to old/wafconf/user_agent
diff --git a/wafconf/white_url b/old/wafconf/white_url
similarity index 100%
rename from wafconf/white_url
rename to old/wafconf/white_url
diff --git a/test.lua b/test.lua
new file mode 100644
index 0000000..480f809
--- /dev/null
+++ b/test.lua
@@ -0,0 +1,41 @@
+--
+-- Created by IntelliJ IDEA.
+-- User: guang
+-- Date: 16/9/22
+-- Time: 下午5:59
+-- To change this template use File | Settings | File Templates.
+--
+
+local _M = {}
+_M.version = '0.1.1'
+
+local util = require "resty.waf.util"
+
+local mt = {__index=_M}
+
+function hello()
+ print("hello world")
+end
+
+local config = {'hello', 'world' }
+
+local _a = {}
+
+
+function _M:new()
+ return setmetatable({}, mt)
+end
+
+function _M:name()
+ local name = {'guang', 'hong', 'wei' }
+ name_new = util.table_copy(name)
+ print(table.concat(name_new, ','))
+end
+
+function _M.get_version()
+ local name = _M.name()
+ print(name)
+end
+
+return _a
+
diff --git a/test2.lua b/test2.lua
new file mode 100644
index 0000000..5cdd09d
--- /dev/null
+++ b/test2.lua
@@ -0,0 +1,31 @@
+--
+-- Created by IntelliJ IDEA.
+-- User: guang
+-- Date: 16/9/22
+-- Time: 下午6:25
+-- To change this template use File | Settings | File Templates.
+--
+
+
+local lua_waf = require "core"
+local iputils = require "iputils"
+
+local waf = lua_waf:new("test")
+local waf2 = lua_waf:new("jj")
+
+for k, v in pairs(waf["config"]) do
+ print(k, v)
+end
+
+waf:set_option("active", true)
+
+for k, v in pairs(waf["config"]) do
+ print(k, v)
+end
+print(waf.config.active)
+
+-- waf:deny_cc()
+-- waf2:deny_cc()
+waf:log("hello world")
+waf2:log("world")
+print(iputils.ip2bin("192.168.1.1"))