国家黑白名单通过 ngx_http_geoip2_module 模块实现
1.下载 libmaxminddb 并编译安装
wget https://github.com/maxmind/libmaxminddb/releases/download/1.4.3/libmaxminddb-1.4.3.tar.gz
tar xvf libmaxminddb-1.4.3.tar.gz
cd libmaxminddb-1.4.3/
./configure
make
make check
make install
ldconfig
sudo sh -c "echo /usr/local/lib >> /etc/ld.so.conf.d/local.conf"
ldconfig
2.下载ngx_http_geoip2_module
wget https://github.com/leev/ngx_http_geoip2_module/archive/3.3.tar.gz
tar xvf 3.3.tar.gz
3.编译动态模块
a.需要先查看已经安装 nginx的版本
[root@devops ~]# nginx -v
nginx version: nginx/1.18.0
b.查看nginx编译的参数
[root@devops ~]# nginx -V
nginx version: nginx/1.18.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'
c.下载源码,并使用相同参数编译,增加动态编译模块 --add-dynamic-module=../ngx_http_geoip2_module-3.3
wget http://nginx.org/download/nginx-1.18.0.tar.gz
tar zxvf nginx-1.18.0.tar.gz
cd nginx-1.18.0
./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie' --add-dynamic-module=../ngx_http_geoip2_module-3.3
make -j4 #不需要 make install
编译好的so 在 objs/ngx_http_geoip2_module.so
cp objs/ngx_http_geoip2_module.so /usr/share/nginx/modules/
NGINX配置
#服务模块到nginx modules 目录
mkdir /usr/share/nginx/modules
cp objs/ngx_http_geoip2_module.so /usr/share/nginx/modules/
cp objs/ngx_http_geoip2_module.so /etc/nginx/modules/ngx_http_geoip2_module.so
#增加geoip2 模块
vim /etc/nginx/nginx.conf
load_module modules/ngx_http_geoip2_module.so;
在 nginx.conf http 配置里面增加
include conf.d/waf/waf.conf ;
在对应的 server 里面添加
#在 server 内添加
include conf.d/waf/status ;
include conf.d/waf/dynamic_limit ;
waf.tar.gz 需要解压到 /etc/nginx/conf.d/ 目录下
nginx,waf配置信息-Linux文档类资源-CSDN下载
分析一下waf内容
black_ip_list ip 黑名单,支持ip段添加 格式: 112.2.3.0/24 1;
dynamic_limit limit_req 和 limit_conn 配置
dynamic_variable limit_req 和 limit_conn 拦截配置
GeoLite2-Country.mmdb geoip 国家库
limit_conn
limit_req
ngx_http_geoip2_module.so
status 服务器黑白名单访问状态码配置
waf.conf 主要配置
white_country_list 国家白名单,格式: CN 1;
white_ip_limit_list limit限制 ip白名单,增加之后,该ip访问,limit 不生效
white_ip_list ip 白名单,格式和ip黑名单一致
waf.conf
geoip2 /etc/nginx/conf.d/waf/GeoLite2-Country.mmdb {
#auto_reload 5m;
$geoip2_metadata_country_build metadata build_epoch;
$geoip2_data_country_code default=LOCAL source=$remote_addr country iso_code;
$geoip2_data_country_name country names en;
#$geoip2_data_country_name country names zh-CN;
#$geoip2_data_country_name country names en;
#$geoip2_data_city_name default=Shanghai city names en;
#$geoip2_data_province_name subdivisions 0 names en;
#$geoip2_data_province_isocode subdivisions 0 iso_code;
}
map $geoip2_data_country_code $allowed_country {
default 0;
LOCAL 1;
include conf.d/waf/white_country_list;
}
geo $remote_addr $ipblacklist {
default 0;
include conf.d/waf/black_ip_list;
}
geo $remote_addr $allowed_ip {
default 0 ;
include conf.d/waf/white_ip_list;
}
geo $limit_white_ip_list {
default 0 ;
include conf.d/waf/white_ip_limit_list;
}
map $limit_white_ip_list $limit {
0 $http_authorization ;
1 "no_limit";
}
map $limit $auth_token { # 首先根据token判断访问速率,如果token不存在,则根据远端ip 判断访问速率
"" $binary_remote_addr;
"~^Bearer(.*)(?<token>.{60}$)" $token; # 这个是根据业务处理,我们每个用户访问服务,header 里面带有token,可以根据token 判断用户访问速率
"no_limit" "";
}
include conf.d/waf/dynamic_variable ;
这个是服务器的配置,手动操作很是繁琐,最好有个可以控制的简单界面
页面采用vue + element-ui
数据库使用的 postgresql
后端使用的nodejs,用Python也都一样,就是一个简单的api访问接口,实现读写文件,重载nginx服务
我先说下我的思路,服务器黑白名单,城市访问白名单,访问速率限制,访问速率白名单,这些功能的数据,先存到数据库里面,然后每次操作,都把数据从数据库读取 和要操作的数据进行处理,处理好之后,写到配置文件里面,然后通过命令检查配置是否正常,如果正常,再通过回调方法把数据写到数据库里面,不正常就回滚配置,提示操作失败
有思路之后,那就开始搞数据表结构
a.一个世界大部分国家的数据表
b.一个服务器黑白名单的数据表
c.速率访问限制配置表
城市国家数据,这个geoip 官方可以找到,
DROP TABLE IF EXISTS "public"."geoip2_data_country_info";
CREATE TABLE "public"."geoip2_data_country_info" (
"code" varchar(4) COLLATE "pg_catalog"."default" NOT NULL,
"cname" varchar(255) COLLATE "pg_catalog"."default",
"ename" varchar(255) COLLATE "pg_catalog"."default",
"isactive" bool DEFAULT false
)
;
COMMENT ON COLUMN "public"."geoip2_data_country_info"."code" IS '国家代码';
COMMENT ON COLUMN "public"."geoip2_data_country_info"."cname" IS '国家英文名称';
COMMENT ON COLUMN "public"."geoip2_data_country_info"."ename" IS '国家中文名称';
COMMENT ON COLUMN "public"."geoip2_data_country_info"."isactive" IS '是否允许该国家ip访问';
服务器黑白名单,库可以这样定义
CREATE TABLE "public"."ipbwlist" (
"ip" varchar(255) COLLATE "pg_catalog"."default" NOT NULL,
"status" bool NOT NULL DEFAULT true,
"des" varchar(255) COLLATE "pg_catalog"."default",
"type" varchar(255) COLLATE "pg_catalog"."default" NOT NULL,
"ctime" int8 NOT NULL
)
;
COMMENT ON COLUMN "public"."ipbwlist"."ip" IS '主机ip地址';
COMMENT ON COLUMN "public"."ipbwlist"."status" IS '状态';
COMMENT ON COLUMN "public"."ipbwlist"."des" IS '备注信息';
COMMENT ON COLUMN "public"."ipbwlist"."type" IS '类型 ,white 表示白名单, black 表示黑名单, limit 表示访问速率限制白名单';
COMMENT ON COLUMN "public"."ipbwlist"."ctime" IS '修改时间';
-- ----------------------------
-- Primary Key structure for table geoip2_data_country_info
-- ----------------------------
ALTER TABLE "public"."geoip2_data_country_info" ADD CONSTRAINT "geoip2_data_country_info_pkey" PRIMARY KEY ("code");
-- ----------------------------
-- Primary Key structure for table ipbwlist
-- ----------------------------
ALTER TABLE "public"."ipbwlist" ADD CONSTRAINT "ipbwlist_pkey" PRIMARY KEY ("ip");
访问速率配置,直接一个 key value 的配置就行
CREATE TABLE "public"."server_config" (
config text,
value text
);
那开始整这个后端,需要先定义一下文件和服务操作
const nginx_base_waf = '/etc/nginx/conf.d/waf/';
module.exports = {
"black_ip_list": nginx_base_waf + 'black_ip_list',
"white_ip_list": nginx_base_waf + 'white_ip_list',
"white_country_list": nginx_base_waf + 'white_country_list',
"white_ip_limit_list": nginx_base_waf + 'white_ip_limit_list',
"limit_conn": nginx_base_waf + 'limit_conn',
"limit_req": nginx_base_waf + 'limit_req',
"nginx_check_cmd": "/usr/sbin/nginx -t -c /etc/nginx/nginx.conf",
"nginx_reload_cmd": "systemctl reload nginx",
"limit_req_tem":'limit_req_zone $auth_token zone=req_zone:100m rate=?#r/m;',
"limit_conn_tem":'limit_conn conn_zone ?#;'
};
还需要写个调用shell命令的,写配置的方法
const fs = require('fs');
const nginxconfig = require('./../config/nginxconfig'); #这个就是上面那个定义的配置文件路径
const tools = require('./tools'); # 这个方法就是打印日志,封装的是log4js 模块
const {exec,} = require('child_process');
async function shellcmd(cmd,callback,failecallback) {
try {
return exec(cmd, (error, stdout, stderr) => {
if (error) {
tools.logerror(`exec error: ${error}`);
return failecallback()
}
tools.loginfo(`stdout: ${stdout}`);
tools.loginfo(`stderr: ${stderr}`);
return callback();
});
}
catch (e) {
tools.logerror(`exec error: ${e}`);
return failecallback()
}
}
async function nginx_check(callback,failecallback) {
tools.loginfo('exec nginx check cmd');
return await shellcmd(nginxconfig.nginx_check_cmd,callback,failecallback);
}
async function nginx_reload(callback,failecallback) {
tools.loginfo('exec nginx reload cmd');
return await shellcmd(nginxconfig.nginx_reload_cmd,callback,failecallback);
}
async function back_conf(filepath,action,cllback){
let target = filepath+'.bak';
if(action ==='restore'){
let tmp = filepath;
filepath = target;
target = tmp;
}
fs.copyFile(filepath,target,function (err) {
if (err) throw err;
tools.loginfo(filepath+' backup success');
return cllback()
})
}
async function write_black_ip_list(str, callback, faileback) {
return await write_file(nginxconfig.black_ip_list, str, callback, faileback)
}
async function write_white_ip_list(str, callback, faileback) {
return await write_file(nginxconfig.white_ip_list, str, callback, faileback)
}
async function write_white_country_list(str, callback, faileback) {
return await write_file(nginxconfig.white_country_list, str, callback, faileback)
}
async function write_white_ip_limit_list(str, callback, faileback) {
return await write_file(nginxconfig.white_ip_limit_list, str, callback, faileback)
}
async function write_limit_conn(str, callback, faileback) {
str = nginxconfig.limit_conn_tem.replace("?#",str);
return await write_file(nginxconfig.limit_conn, str, callback, faileback)
}
async function write_limit_req(str, callback, faileback) {
str = nginxconfig.limit_req_tem.replace("?#",str);
return await write_file(nginxconfig.limit_req, str, callback, faileback)
}
async function write_file(filepath, str, callback, faileback) {
try {
fs.open(filepath, 'wx', (err,fd)=> {
if (err) {
if (err.code !== 'EEXIST') {
tools.logerror(err);
return faileback()
}
}
return back_conf(filepath,'backup', function () {
return fs.writeFile(filepath, str, 'utf8', function (err) {
if (err) {
tools.logerror(err);
return faileback()
}
tools.loginfo(filepath+' file save success');
return nginx_check( function () {
return nginx_reload(function () {
return callback()
},function () {
tools.logerror('nginx reload failed');
return faileback()
});
}, function () {
tools.logerror('nginx check failed');
return back_conf(filepath,'restore',function () {
return faileback()
});
})
});
});
});
} catch (e) {
tools.logerror(e);
return faileback()
}
}
module.exports = {
write_black_ip_list,
write_white_country_list,
write_white_ip_list,
write_white_ip_limit_list,
write_limit_conn,
write_limit_req,
};
既然核心的都完事了,那就需要处理前端传的数据,保存操作吧
大体上有三种操作
- 保存数据到服务器和数据库
- 删除数据到服务器和数据库
- 开启关闭 【开启:相当于保存要操作的数据到服务器,并更新数据库,关闭:相当于删除要操作的数据到服务器,并更新数据库】
根据这些操作,需要写一个公共的数据操作方法