limit_ip_access.lua
4.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
local modname= ...
local M={}
_G[modname]=M
package.loaded[modname]=M
local cjson=require "cjson"
local rate_limit = require "limit_common_flow"
local iptool=require "iptool"
local lrucache = require "resty.lrucache"
local cache=lua_context.mal_ip_cache
local redis_limit_ip=lua_context["redis_limit_ip"]
function M.in_array(value,arr)
if not value then
return false
end
if not arr then
return false
end
for k, v in ipairs(arr) do
if value==v then
return true
end
end
return false
end
function M:get_req_param(req_param)
local method = ngx.var.request_method
if "GET" == method then
return ngx.req.get_uri_args()[req_param]
else
ngx.req.read_body()
return ngx.req.get_post_args()[req_param]
end
end
--1:api 2:service
function M:limit_ip_access()
local limit_ip_config=lua_context.configs["limit_ip_access"]
local common_config=lua_context.configs["common_conf"]
-- global switch control
if not common_config.lua_golbal_switch then
return
end
-- is open ip limit access control
if not limit_ip_config.is_open then
return
end
local ip=ngx.var.real_ip
if not ip then
return
end
--check is in white ip list
local white_ips_length=#limit_ip_config.white_ips
if white_ips_length >0 then
for i=1,white_ips_length do
local is_in_white_ips=iptool:pcall_check_ip_in_ipblock(ip,limit_ip_config.white_ips[i],false)
if is_in_white_ips then
return
end
end
end
-- check ip is in limit ip list
local is_limit=self.in_array(ip,limit_ip_config.limit_ip_config)
local limit_type="0"
-- check ip access is arrive max access
local ip_qps_limit=limit_ip_config.ip_qps_limit
if (not is_limit) and ip_qps_limit and ip_qps_limit[1] and ip_qps_limit[2] then
if not rate_limit.limit_flow("yh:limit:ip:" .. ip,limit_ip_config.ip_qps_limit[1],limit_ip_config.ip_qps_limit[2]) then
is_limit=true
limit_type="1"
end
end
-- check method or uri limit
local req_uri_method
local method_limit_conf
if(not is_limit) and limit_ip_config.interface_ip_qps_limit then
req_uri_method = self:get_req_param("method")
if not req_uri_method then
req_uri_method = ngx.var.uri
end
method_limit_conf=limit_ip_config.interface_ip_qps_limit[req_uri_method]
end
if (not is_limit) and req_uri_method and method_limit_conf then
if not rate_limit.limit_flow("yh:limit:ip:" .. ip .. ":" .. req_uri_method,method_limit_conf[1],method_limit_conf[2]) then
is_limit=true
limit_type="2"
end
end
local is_white_method=self.in_array(req_uri_method,limit_ip_config.white_method)
if is_white_method then
return
end
-- check redis config
if not is_limit then
local res=cache:get("yh:mip:" .. ip)
if res then
is_limit=true
limit_type="3"
end
end
if is_limit then
ngx.log(ngx.ERR, "[LimitIPAccess:ip]:" .. ip .. ",type:" .. limit_type)
ngx.header["Content-type"]="application/json;charset=utf-8"
if limit_type=="3" then
ngx.header["x-yoho-malicode"]="10011"
end
ngx.exit(ngx.HTTP_OK)
end
end
-- malicious ip
function M:mal_ip()
local method=self:get_req_param("method")
local ips=self:get_req_param("ips")
local expire=self:get_req_param("expire")
ngx.header["Content-type"]="application/json;charset=utf-8"
if not method or not ips then
ngx.say('{"code": 400, "msg": "params error!"}')
ngx.exit(ngx.HTTP_OK)
end
if method == 'publish' then
local t={}
t.ips=ips
t.expire=expire
redis_limit_ip:cmd("publish","mal_ips",cjson.encode(t))
end
local exists={}
for ip in string.gmatch(ips,"[^',']+") do
if method == 'add' then
local expire= (not expire) and 86400 or expire
cache:set("yh:mip:" .. ip,"1",expire)
elseif method == 'del' then
cache:delete("yh:mip:" .. ip)
elseif method == 'exists' then
local res=cache:get("yh:mip:" .. ip)
res= res and true or false
exists[#exists+1]=tostring(res)
end
end
local body=table.concat(exists,",")
ngx.say('{"code": 200, "msg": "'.. body ..'"}')
ngx.exit(ngx.HTTP_OK)
end