• nginx主机黑白名单[geoip]


    国家黑白名单通过 ngx_http_geoip2_module 模块实现

    1.下载 libmaxminddb 并编译安装

    1. wget https://github.com/maxmind/libmaxminddb/releases/download/1.4.3/libmaxminddb-1.4.3.tar.gz
    2. tar xvf libmaxminddb-1.4.3.tar.gz 
    3. cd libmaxminddb-1.4.3/
    4. ./configure
    5. make
    6. make check
    7. make install
    8. ldconfig 
    9. sudo sh -c "echo /usr/local/lib  >> /etc/ld.so.conf.d/local.conf"
    10. ldconfig

    2.下载ngx_http_geoip2_module

    1. wget https://github.com/leev/ngx_http_geoip2_module/archive/3.3.tar.gz
    2. tar xvf 3.3.tar.gz

    3.编译动态模块

    a.需要先查看已经安装 nginx的版本

    1. [root@devops ~]# nginx -v
    2. nginx version: nginx/1.18.0

    b.查看nginx编译的参数

    1. [root@devops ~]# nginx -V
    2. nginx version: nginx/1.18.0
    3. built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC) 
    4. built with OpenSSL 1.0.2k-fips  26 Jan 2017
    5. TLS SNI support enabled
    6. 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

    1. wget http://nginx.org/download/nginx-1.18.0.tar.gz
    2. tar zxvf nginx-1.18.0.tar.gz
    3. 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 目录

    1. mkdir /usr/share/nginx/modules
    2. cp objs/ngx_http_geoip2_module.so /usr/share/nginx/modules/
    3. cp objs/ngx_http_geoip2_module.so /etc/nginx/modules/ngx_http_geoip2_module.so

    #增加geoip2 模块

    1. vim /etc/nginx/nginx.conf
    2. load_module modules/ngx_http_geoip2_module.so;
    在 nginx.conf http 配置里面增加
    include conf.d/waf/waf.conf ;

    在对应的 server 里面添加

    1. #在 server 内添加
    2. include conf.d/waf/status ;
    3. include conf.d/waf/dynamic_limit ;

    waf.tar.gz  需要解压到 /etc/nginx/conf.d/ 目录下

    nginx,waf配置信息-Linux文档类资源-CSDN下载

    分析一下waf内容

    1. black_ip_list                ip 黑名单,支持ip段添加 格式: 112.2.3.0/24 1;
    2. dynamic_limit                limit_req 和 limit_conn 配置
    3. dynamic_variable             limit_req 和 limit_conn 拦截配置 
    4. GeoLite2-Country.mmdb        geoip 国家库
    5. limit_conn                    
    6. limit_req
    7. ngx_http_geoip2_module.so
    8. status                       服务器黑白名单访问状态码配置 
    9. waf.conf                     主要配置
    10. white_country_list           国家白名单,格式: CN 1;
    11. white_ip_limit_list          limit限制 ip白名单,增加之后,该ip访问,limit 不生效
    12. white_ip_list                ip 白名单,格式和ip黑名单一致

    waf.conf

    1. geoip2 /etc/nginx/conf.d/waf/GeoLite2-Country.mmdb {
    2.     #auto_reload 5m;
    3.     $geoip2_metadata_country_build metadata build_epoch;
    4.     $geoip2_data_country_code default=LOCAL source=$remote_addr country iso_code;
    5.     $geoip2_data_country_name country names en;
    6.     #$geoip2_data_country_name country names zh-CN;
    7.     #$geoip2_data_country_name country names en;
    8.     #$geoip2_data_city_name default=Shanghai city names en;
    9.     #$geoip2_data_province_name subdivisions 0 names en;
    10.     #$geoip2_data_province_isocode subdivisions 0 iso_code;
    11. }
    12. map $geoip2_data_country_code $allowed_country {
    13.     default 0;
    14.     LOCAL 1;
    15.     include conf.d/waf/white_country_list;
    16. }
    17. geo $remote_addr $ipblacklist {
    18.     default 0;
    19.     include conf.d/waf/black_ip_list;
    20. }
    21. geo $remote_addr $allowed_ip {
    22.     default 0 ;
    23.     include conf.d/waf/white_ip_list;
    24. }
    25. geo $limit_white_ip_list {
    26.     default 0 ;
    27.     include conf.d/waf/white_ip_limit_list;
    28. }
    29. map $limit_white_ip_list $limit {
    30.     0 $http_authorization ;
    31.     1 "no_limit";
    32. }
    33. map $limit $auth_token {  # 首先根据token判断访问速率,如果token不存在,则根据远端ip 判断访问速率
    34. "" $binary_remote_addr;
    35. "~^Bearer(.*)(?.{60}$)" $token# 这个是根据业务处理,我们每个用户访问服务,header 里面带有token,可以根据token 判断用户访问速率
    36. "no_limit" "";
    37. }
    38. include conf.d/waf/dynamic_variable ;

    这个是服务器的配置,手动操作很是繁琐,最好有个可以控制的简单界面


    页面采用vue + element-ui 

    数据库使用的 postgresql

    后端使用的nodejs,用Python也都一样,就是一个简单的api访问接口,实现读写文件,重载nginx服务


    我先说下我的思路,服务器黑白名单,城市访问白名单,访问速率限制,访问速率白名单,这些功能的数据,先存到数据库里面,然后每次操作,都把数据从数据库读取 和要操作的数据进行处理,处理好之后,写到配置文件里面,然后通过命令检查配置是否正常,如果正常,再通过回调方法把数据写到数据库里面,不正常就回滚配置,提示操作失败


    有思路之后,那就开始搞数据表结构

    a.一个世界大部分国家的数据表

    b.一个服务器黑白名单的数据表

    c.速率访问限制配置表

    城市国家数据,这个geoip 官方可以找到,

    1. DROP TABLE IF EXISTS "public"."geoip2_data_country_info";
    2. CREATE TABLE "public"."geoip2_data_country_info" (
    3.   "code" varchar(4) COLLATE "pg_catalog"."default" NOT NULL,
    4.   "cname" varchar(255) COLLATE "pg_catalog"."default",
    5.   "ename" varchar(255) COLLATE "pg_catalog"."default",
    6.   "isactive" bool DEFAULT false
    7. )
    8. ;
    9. COMMENT ON COLUMN "public"."geoip2_data_country_info"."code" IS '国家代码';
    10. COMMENT ON COLUMN "public"."geoip2_data_country_info"."cname" IS '国家英文名称';
    11. COMMENT ON COLUMN "public"."geoip2_data_country_info"."ename" IS '国家中文名称';
    12. COMMENT ON COLUMN "public"."geoip2_data_country_info"."isactive" IS '是否允许该国家ip访问';

    服务器黑白名单,库可以这样定义

    1. CREATE TABLE "public"."ipbwlist" (
    2.   "ip" varchar(255) COLLATE "pg_catalog"."default" NOT NULL,
    3.   "status" bool NOT NULL DEFAULT true,
    4.   "des" varchar(255) COLLATE "pg_catalog"."default",
    5.   "type" varchar(255) COLLATE "pg_catalog"."default" NOT NULL,
    6.   "ctime" int8 NOT NULL
    7. )
    8. ;
    9. COMMENT ON COLUMN "public"."ipbwlist"."ip" IS '主机ip地址';
    10. COMMENT ON COLUMN "public"."ipbwlist"."status" IS '状态';
    11. COMMENT ON COLUMN "public"."ipbwlist"."des" IS '备注信息';
    12. COMMENT ON COLUMN "public"."ipbwlist"."type" IS '类型 ,white  表示白名单,  black 表示黑名单, limit 表示访问速率限制白名单';
    13. COMMENT ON COLUMN "public"."ipbwlist"."ctime" IS '修改时间';
    14. -- ----------------------------
    15. -- Primary Key structure for table geoip2_data_country_info
    16. -- ----------------------------
    17. ALTER TABLE "public"."geoip2_data_country_info" ADD CONSTRAINT "geoip2_data_country_info_pkey" PRIMARY KEY ("code");
    18. -- ----------------------------
    19. -- Primary Key structure for table ipbwlist
    20. -- ----------------------------
    21. ALTER TABLE "public"."ipbwlist" ADD CONSTRAINT "ipbwlist_pkey" PRIMARY KEY ("ip");

    访问速率配置,直接一个 key value 的配置就行

    1. CREATE TABLE "public"."server_config" (
    2.     config text,
    3.     value text
    4. );

    那开始整这个后端,需要先定义一下文件和服务操作

    1. const nginx_base_waf = '/etc/nginx/conf.d/waf/';
    2. module.exports = {
    3.     "black_ip_list": nginx_base_waf + 'black_ip_list',
    4.     "white_ip_list": nginx_base_waf + 'white_ip_list',
    5.     "white_country_list": nginx_base_waf + 'white_country_list',
    6.     "white_ip_limit_list": nginx_base_waf + 'white_ip_limit_list',
    7.     "limit_conn": nginx_base_waf + 'limit_conn',
    8.     "limit_req": nginx_base_waf + 'limit_req',
    9.     "nginx_check_cmd""/usr/sbin/nginx -t -c /etc/nginx/nginx.conf",
    10.     "nginx_reload_cmd""systemctl reload nginx",
    11.     "limit_req_tem":'limit_req_zone $auth_token zone=req_zone:100m rate=?#r/m;',
    12.     "limit_conn_tem":'limit_conn conn_zone ?#;'
    13. };

    还需要写个调用shell命令的,写配置的方法

    1. const fs = require('fs');
    2. const nginxconfig = require('./../config/nginxconfig');  #这个就是上面那个定义的配置文件路径
    3. const tools = require('./tools');  # 这个方法就是打印日志,封装的是log4js 模块
    4. const {exec,} = require('child_process');
    5. async function shellcmd(cmd,callback,failecallback) {
    6.     try {
    7.         return exec(cmd, (error, stdout, stderr) => {
    8.             if (error) {
    9.                 tools.logerror(`exec error: ${error}`);
    10.                 return failecallback()
    11.             }
    12.             tools.loginfo(`stdout: ${stdout}`);
    13.             tools.loginfo(`stderr: ${stderr}`);
    14.             return callback();
    15.         });
    16.     }
    17.     catch (e) {
    18.         tools.logerror(`exec error: ${e}`);
    19.         return failecallback()
    20.     }
    21. }
    22. async function nginx_check(callback,failecallback) {
    23.     tools.loginfo('exec nginx check cmd');
    24.     return await shellcmd(nginxconfig.nginx_check_cmd,callback,failecallback);
    25. }
    26. async function nginx_reload(callback,failecallback) {
    27.     tools.loginfo('exec nginx reload cmd');
    28.     return  await shellcmd(nginxconfig.nginx_reload_cmd,callback,failecallback);
    29. }
    30. async function back_conf(filepath,action,cllback){
    31.     let target = filepath+'.bak';
    32.     if(action ==='restore'){
    33.         let tmp = filepath;
    34.         filepath = target;
    35.         target = tmp;
    36.     }
    37.     fs.copyFile(filepath,target,function (err) {
    38.         if (err) throw err;
    39.        tools.loginfo(filepath+' backup success');
    40.         return cllback()
    41.     })
    42. }
    43. async function write_black_ip_list(str, callback, faileback) {
    44.     return await write_file(nginxconfig.black_ip_list, str, callback, faileback)
    45. }
    46. async function write_white_ip_list(str, callback, faileback) {
    47.     return await write_file(nginxconfig.white_ip_list, str, callback, faileback)
    48. }
    49. async function write_white_country_list(str, callback, faileback) {
    50.     return await write_file(nginxconfig.white_country_list, str, callback, faileback)
    51. }
    52. async function write_white_ip_limit_list(str, callback, faileback) {
    53.     return await write_file(nginxconfig.white_ip_limit_list, str, callback, faileback)
    54. }
    55. async function write_limit_conn(str, callback, faileback) {
    56.     str = nginxconfig.limit_conn_tem.replace("?#",str);
    57.     return await write_file(nginxconfig.limit_conn, str, callback, faileback)
    58. }
    59. async function write_limit_req(str, callback, faileback) {
    60.     str = nginxconfig.limit_req_tem.replace("?#",str);
    61.     return await write_file(nginxconfig.limit_req, str, callback, faileback)
    62. }
    63. async function write_file(filepath, str, callback, faileback) {
    64.     try {
    65.         fs.open(filepath, 'wx'(err,fd)=> {
    66.             if (err) {
    67.                 if (err.code !== 'EEXIST') {
    68.                     tools.logerror(err);
    69.                     return faileback()
    70.                 }
    71.             }
    72.             return  back_conf(filepath,'backup'function () {
    73.                 return fs.writeFile(filepath, str, 'utf8',  function (err) {
    74.                     if (err) {
    75.                         tools.logerror(err);
    76.                         return faileback()
    77.                     }
    78.                     tools.loginfo(filepath+' file save success');
    79.                     return  nginx_checkfunction () {
    80.                         return  nginx_reload(function () {
    81.                             return callback()
    82.                         },function () {
    83.                             tools.logerror('nginx reload failed');
    84.                                 return faileback()
    85.                         });
    86.                     }, function () {
    87.                         tools.logerror('nginx check failed');
    88.                         return  back_conf(filepath,'restore',function () {
    89.                             return faileback()
    90.                         });
    91.                     })
    92.                 });
    93.             });
    94.         });
    95.     } catch (e) {
    96.         tools.logerror(e);
    97.         return faileback()
    98.     }
    99. }
    100. module.exports = {
    101.     write_black_ip_list,
    102.     write_white_country_list,
    103.     write_white_ip_list,
    104.     write_white_ip_limit_list,
    105.     write_limit_conn,
    106.     write_limit_req,
    107. };

    既然核心的都完事了,那就需要处理前端传的数据,保存操作吧

    大体上有三种操作

    1. 保存数据到服务器和数据库

    2. 删除数据到服务器和数据库

    3. 开启关闭 【开启:相当于保存要操作的数据到服务器,并更新数据库,关闭:相当于删除要操作的数据到服务器,并更新数据库】

    根据这些操作,需要写一个公共的数据操作方法

  • 相关阅读:
    牛客小白月赛59
    深度学习【DL介绍、神经网络介绍】
    c++多源BFS
    运动检测辅助系统
    iOS MD5基础知识
    猿创征文|工具百宝箱-数据库连接工具-接口调试与测试工具-抓包工具
    Kafka集群中Controller,Rebalance,HW的区别
    【Java基础】继承的实现及继承中变量、构造方法、成员方法的访问特点
    什么是容错性(Fault Tolerance)?解释容错性的实现方法
    CSRF和XSS是什么?
  • 原文地址:https://blog.csdn.net/ly1358152944/article/details/126466723