用函数式思维写 shell 之 unban_the_ip 脚本

shell 练习:用函数式思维写 shell,以服务器安全-封锁 ip/解封 ip 作为示例。


unban_the_ip 脚本代码

#!/bin/bash
# desc: 解禁 ip(即:黑名单数据删除操作)
# author: echoxu
# 功能:
#       1. 命令行中添加要解禁的 ip,支持批量操作
#       2: 可解禁指定文件里的 ip,支持批量操作

. lib/common
. lib/firewall
. lib/nginx
. lib/blacklist


args_arr=()


# 组成非第一个参数外的所有参数列表
analysis_args(){ 
    args=$@

    for arg in $args
    do
        args_arr[${#args_arr[*]}]=${arg}
    done

    unset args_arr[0]  # 删除第一个元素,即传入的 flag 的值
}


# 重启 nginx/firewalld 的 handler 函数
relaod_handler(){
    block_ip_type=$(get_section_value_from_config_path block_ip_type)
    code=$?
    print_return_code_message_of_get_section_path $code

    case "$block_ip_type" in
    firewalld)
        block_ip_type=firewalld_reload
        ;;
    nginx)
        block_ip_type=reload_nginx
        ;;
    esac

    echo $block_ip_type


}


# 统计返回值,当返回值为 0 的个数大于 1 时才能重启防火墙
# 也可以通过判断 blacklist 或者 blockip.conf 文件是否被修改来决定是否重启
reload_of_block_ip_type(){
    succeed_code_count=0
    for i in `cat /tmp/add_ip_to_blacklist_return_code`
    do
        if [ $i -eq 0 ];then
            let succeed_code_count++
        fi

    done

    if [ $succeed_code_count -gt 0 ];then
        reload_res=$(relaod_handler)
        $reload_res
    fi
    
}


# 将操作记录到日志中
record_logs_of_unban_ip(){
    to_log=$1
    log_path=$2

    echo "$(date +'%F-%T') 解禁ip: $to_log " >> $log_path
}


# handler 函数
get_block_ip_type_of_unban_ip_handler(){
    block_ip_type_input=$1

    case "$block_ip_type_input" in
    firewalld)
        block_ip_type_input=firewall_op_with_remove
        ;;
    nginx)
        block_ip_type_input=nginx_record_remove
        ;;
    esac

    echo $block_ip_type_input
}


# 从命令行中解封一个或多个 ip
unban_the_ip(){
    for arg in ${args_arr[*]}
    do
        is_ip_result=$(isip_from_input $arg)
        code=$?
        if [ $code != 0 ];then
            err_code $code "$arg 不符合 ip 格式,请确认后再操作..."
            echo $code >> /tmp/add_ip_to_blacklist_return_code
            continue
        else
            arg=$is_ip_result
        fi

        if [ "$block_ip_type" = "firewalld" ];then
            delete_ip_from_blacklist $arg
            code=$?
            if [ $code -eq 144 ];then
                err_code $code "IP: $arg 在黑名单文件中不存在..."
                continue
            fi
        fi

        $block_ip_type_result $arg
        code=$?
        echo $code >> /tmp/add_ip_to_blacklist_return_code
        if [ $code = 0 ];then
            record_logs_of_unban_ip $arg $log_path
        fi
      
    done

}


# 批量解封 ip: 从文件中获取待解禁的 ip
unban_the_ip_from_file(){
    unban_ip_file_path=$1

    real_path=$(get_real_path $unban_ip_file_path)
    is_file_res=$(vaild_is_path_from_input $real_path)
    code=$?
    if [ $code != 0 ];then
        print_message_of_vaild_is_path_from_input $code $real_path
    else
        unban_ip_file_path=$is_file_res
    fi
    
    for ip_from_file in `cat $unban_ip_file_path`
    do
        is_ip_result=$(isip_from_input $ip_from_file)
        code=$?
        if [ $code != 0 ];then
            err_code $code "$ip_from_file 不符合 ip 格式,请重新输入..."
            echo $code >> /tmp/add_ip_to_blacklist_return_code
            continue
        fi

        if [ "$block_ip_type" = "firewalld" ];then
            delete_ip_from_blacklist $ip_from_file
            code=$?
            if [ $code -eq 144 ];then
                err_code $code "IP: $ip_from_file 在黑名单文件中不存在..."
                continue
            fi
        fi

        $block_ip_type_result $ip_from_file
        code=$?
        echo $code >> /tmp/add_ip_to_blacklist_return_code
        if [ $code = 0 ];then
            record_logs_of_unban_ip $ip_from_file $log_path
        fi
    done
       
}


# 路由函数
unban_the_ip_router(){
    args=$@
    flag=$1
    args_number=$#
    to_unban_filepath=$2

    # 清空返回值
    cat /dev/null > /tmp/add_ip_to_blacklist_return_code

    # 获取 封禁/解禁 ip 的方式
    block_ip_type=$(get_section_value_from_config_path block_ip_type)
    code=$?
    print_return_code_message_of_get_section_path $code

    block_ip_type_result=$(get_block_ip_type_of_unban_ip_handler $block_ip_type)


    # 防火墙状态检查
    if [[ $block_ip_type_result == "firewall_op_with_remove" ]];then
        firewall_status=$(check_firewall_status)
        code=$?
        print_message_of_check_firewall_status $code
    fi

    # 获取日志文件存储路径(获取一次即可,所以写在这里)
    log_path=$(get_section_value_from_config_path server_secure_log_path)
    code=$?
    print_return_code_message_of_get_section_path $code

    # 判断参数
    case "$flag" in
    -u)
        # 指定这个 flag 时,总参数个数不能小于 2
        if [ $args_number -lt 2 ];then
            echo -e "${Error}: 总参数个数不能小于 2"
            exit 1
        fi

        analysis_args $@
        unban_the_ip
        ;;
    -f)
        # 指定这个 flag 时,总参数个数不能大于 2
        if [[ $args_number -gt 2 || $args_number -lt 2 ]];then
            echo -e "${Error}: 总参数个数不能小于 2 且不能大于 3"
            exit 1
        fi

        unban_the_ip_from_file $to_unban_filepath
        ;;
    *)
        echo -e "${Error}: Usage: $0 -u 单个或多个 ip|-f 文件路径"
        echo -e "${Info}: -u: 解封单个或多个 ip"
        echo -e "${Info}: -f: 从指定的文件里读取 ip 并解封"
        exit 1
    ;;
    esac

    reload_of_block_ip_type
}


unban_the_ip_router $@
上次更新:
贡献者: iEchoxu