草庐IT

openwrt临时封禁ip

大漠飞沙 2023-03-28 原文
用的openwrt路由器,家里宽带申请了动态公网ip,为了方便把22 80端口映射到公网,发现经常被暴力破解,自己写了个临时封禁ip功能的脚本,实现5分钟内同一个ip登录密码错误10次就封禁这个ip 5分钟,并且进行邮件通知

使用步骤

openwrt为19.07.03版本,其他版本没有测试过

  1. 安装bash msmtp

    • opkg update;opkg install bash msmtp
  2. 添加脚本/root/port-security.sh,内容参考下面附件,主要修改通知的邮箱

  3. 脚本增加执行权限

    • chmod a+x /root/port-security.sh
  4. 添加定时任务 crontab -e,10分钟执行一次脚本,如果脚本已经在跑会自动退出当前进程

    • */10 * * * * /root/port-security.sh &
  5. 修改/etc/msmtprc 文件,内容参考下面附件,封禁ip后发送邮件通知

解释

  1. 通过logread查看日志确定被登录的错误次数并且提取要封禁的ip,ssh登录密码错误通过"Bad password attempt for"匹配,web登录密码错误通过"luci: failed login on",具体可以根据实际修改,logread日志过多有用信息有可能被冲掉的可能,可以加大日志缓存或者修改日志等级减少日志
  2. ip封禁是通过ipset配合iptables处理,当要封禁的ip很多的时候,比直接多条iptables性能高,封禁时间由ipset来处理,不需要另外处理封禁时间
  3. 用了bash字典,脚本需要用/bin/bash,不能用/bin/sh,bash低版不支持字典
  4. 内网192.168.0.0/16加入了白名单,如果要用内网来测试,需要注释iptables -I INPUT -s 192.168.0.0/16 -j ACCEPT

/root/port-security.sh

#! /bin/bash

#允许尝试错误的次数
tryErrNum=10
#允许尝试错误在多长时间范围,单位秒,与tryErrNum一起生效
tryTimeOut=300
#需要被封禁的多个ip字符串,逗号隔开,这里为空
dropIpList=""
#logread里面标识字符串,Bad password attempt for 是ssh root登录密码错误log,luci: failed login on 是登录web错误log
errStr=("Bad password attempt for" "luci: failed login on")
#查询logread 日志的时间间隔,单位秒
timesleep=30

#从根据字符串从日志里面提取要封禁的ip,追加到 dropIpList 变量
getdropip() {
    #对过滤的日志倒叙
    lines=$(logread | grep $1 | sed -n '1!G;h;$p')
    linesNum=$(echo -n "$lines" | wc -l)
    #定义字典变量
    declare -A dict
    #
    if [ "$linesNum" -gt "$tryErrNum" ];then
        while read line;
        do
            ip=$(echo -n "$line" | awk '{print $NF}' | awk -F":" '{print $1}')
            time=$(echo -n "$line" | awk '{print $4}' | awk -F":" '{sum += $1*3600 + $2*60 + $3};END {print sum}')
            ok=${dict[$ip]}
            if [ -z $ok ];then
                dict[$ip]=1
                time=$(date | awk '{print $4}' | awk -F":" '{sum += $1*3600 + $2*60+ $3};END {print sum}')
                dict[${ip}_endtime]=$time
            else
                if [ ${dict[$ip]} -lt "$tryErrNum" ];then
                    dict[$ip]=$(expr ${dict[$ip]} + 1)
                    dict[${ip}_starttime]=$time
                fi
            fi
        done < <(echo -n "$lines")

        for key in ${!dict[@]};
        do
            if ! [[ "$key" =~ "starttime" ]] && ! [[ "$key" =~ "endtime" ]];then
                if [ ${dict[$key]} -eq "$tryErrNum" ];then
                    timeDiff=$(expr ${dict[${key}_endtime]} - ${dict[${key}_starttime]})
                    if [ "$timeDiff" -gt 0 ] && [ "$timeDiff" -lt "$tryTimeOut" ];then
                        #追加需要封禁的ip到变量
                        dropIpList=$dropIpList,$key
                    fi
                fi
            fi
        done

    fi

}

#errStr 字符串遍历,分别从log里面匹配,提取要封禁ip
startGetDropIp(){
    i=0
    while :
    do
            errstr=${errStr[$i]}
            if [ -z "$errstr" ];then
                    break
            fi
            i=$(expr $i + 1)

        getdropip $errstr

    done
}

#初始化ipset iptable
intEnv(){
    ipset list BlockIpList
    if  ! [ "$?" == 0 ];
    then
        ipset create BlockIpList hash:net timeout 300
        iptables -I INPUT -m set --match-set BlockIpList src -p tcp -m tcp --dport 22 -j DROP
        iptables -I INPUT -m set --match-set BlockIpList src -p tcp -m tcp --dport 80 -j DROP
        iptables -I INPUT -s 192.168.0.0/16 -j ACCEPT
    fi
}
#把要封禁的ip添加到ipset BlockIpList集合
ipsetAddIp(){
    dropIpListNew=""
    for ip in $(echo -n "$dropIpList" | sed 's/,/ /g')
    do
        ipset add BlockIpList $ip
        if [ "$?" -eq 0 ];then
            dropIpListNew=$dropIpListNew,$ip
        fi
    done
}

sendmail(){
    if [ -n "$dropIpListNew" ];then
        #邮箱填自己常用邮箱,方便及时收到通知
        echo -e  "subject:MyOpenwrt IP封禁提醒\n\n$dropIpListNew" | msmtp 1234567@qq.com
    fi

}

#检查当前进程是否存在
PocessNum=$(ps | grep $0 | grep -v grep | wc -l)
if [ "$PocessNum" -gt 2 ];then
    #已经存在进程,直接退出当前进程
    kill -9 $$
else
    intEnv

    while :
    do
        sleep $timesleep
        dropIpList=""
        startGetDropIp
        ipsetAddIp
        sendmail
    done
fi

/etc/msmtprc 这里用的163邮箱,其他邮箱这里不列举

defaults

account 163
host smtp.163.com
port 25
from <这里填你发邮件的邮箱>
auth plain
tls on
user <这里填你发邮件的邮箱>
password <这里填你发邮件的邮箱的密码>

account default : 163

有关openwrt临时封禁ip的更多相关文章

  1. ruby - 从 Ruby 中的主机名获取 IP 地址 - 2

    我有一个存储主机名的Ruby数组server_names。如果我打印出来,它看起来像这样:["hostname.abc.com","hostname2.abc.com","hostname3.abc.com"]相当标准。我想要做的是获取这些服务器的IP(可能将它们存储在另一个变量中)。看起来IPSocket类可以做到这一点,但我不确定如何使用IPSocket类遍历它。如果它只是尝试像这样打印出IP:server_names.eachdo|name|IPSocket::getaddress(name)pnameend它提示我没有提供服务器名称。这是语法问题还是我没有正确使用类?输出:ge

  2. ruby - 在 TCPServer (Ruby) 中,我如何从客户端获取 IP/MAC? - 2

    我想在Ruby的TCPServer中获取客户端的IP地址。以及(如果可能的话)MAC地址。例如,Ruby中的时间服务器,请参阅评论。tcpserver=TCPServer.new("",80)iftcpserverputs"Listening"loopdosocket=tcpserver.acceptifsocketThread.newdoputs"Connectedfrom"+#HERE!HowcanigettheIPAddressfromtheclient?socket.write(Time.now.to_s)socket.closeendendendend非常感谢!

  3. ruby - 没有 nginx 的 Puma - 同一 IP 上的多个 ruby​​ 应用程序 :PORT - 2

    Nginx在生产中的重要性通常基于它为慢速客户端提供服务的能力;在RESTfulAPI的设置中,它似乎是生产堆栈的一个不必要的层,尤其是Puma(不像广泛使用的unicorn可以处理nginx工作)。Pumacanallowmultipleslowclientstoconnectwithoutrequiringaworkertobeblockedontherequesttransaction.Becauseofthis,Pumahandlesslowclientsgracefully.HerokurecommendsPumaforuseinscenarioswhereyouexpect

  4. Java IP归属地查询(离线方式+在线方式,内附查询IP方法) - 2

    一、离线方式1.1.下载ip2region.xdbGitHub项目地址:https://github.com/lionsoul2014/ip2region我们首先需要下载一个ip2region.xdb的文件下载地址:https://github.com/lionsoul2014/ip2region/blob/master/data/ip2region.xdb打开后点击如图的Download图标即可下载。下载完成后,需要将该文件放到我们的项目中。ps:我是直接放到服务器的,因为放在项目的资源文件夹下,当我们调试的时候使用JavaSpring自带的工具去获取该文件的绝对路径时,没有任何问题,能够正

  5. IP数据报格式 - 2

    1、报文格式前几篇总结过较多网络层的知识,ARP,ip地址、子网掩码等等。这次总结一下IP数据报的报文格式IP数据报的格式能够说明IP协议都具有什么功能。在TCP/IP的标准中,各种数据格式常常以32位(4字节)为单位来描述的。wireshark中IP数据报文呈现一个IP数据报文由首部和数据两部分组成。首部的前一部分是固定长度,共20字节。是所有IP数据报文必须具有的。在首部的固定部分的后面是一些可选字段,其长度可变。2、首部个字段意义  1、版本占4位,指IP协议的版本。通信双方使用的IP协议的版本必须一致。目前广泛使用的IP协议版本号为4(即IPv4)。版本号为6(即IPv6)  2、首部

  6. ruby-on-rails - Ruby 自动删除临时文件? - 2

    我很困惑。这是我的代码:require'csv'require'tempfile'f=Tempfile.new('csv','/tmp')f.write'justwannatest'f.closepf.path如果我打开输出路径,它是空的。我认为这是因为每次ruby​​session退出时,TempFile都会自动从文件系统中删除。但是,我如何确切知道文件何时被删除?因为我想用它在我的Rails应用程序中创建临时文件,我担心文件在使用前是否被删除了。 最佳答案 来自文档:WhenaTempfileobjectisgarbagecol

  7. ruby-on-rails - Ruby/Rails 中 CIDR 的 IP 范围? - 2

    我想做两件事:将IP地址输入转换为CIDR以下是一些示例输入:1.1.1.1192.168.*.*#=>192.168.0-255.0-255192.168.1.2-201.1.1-10.1-100检查给定的IP地址是否属于任何CIDR。这一定是一个非常快速的查询,因为它是我的网络应用程序中非常常见的查找。我正在考虑做这样的事情:defmatches?(request)valid=@ips.select{|cidr|cidr.contains?(request.remote_ip)}!valid.empty?end我认为将IP范围转换为CIDR将使查找速度比我们现在所做的更快,后者将I

  8. ruby - 如何在 ruby​​ 中获取 ip 地址、referer 和用户代理? - 2

    我想记录用户的ip地址、referer和用户代理。在PHP中,我可以从以下变量中获取它们:$_SERVER['REMOTE_ADDR']$_SERVER['HTTP_REFERER']$_SERVER['HTTP_USER_AGENT']如何在ruby​​中获取它们? 最佳答案 PHP嵌入在网络服务器中。Ruby是一种通用语言:如果您需要Web服务器上下文,则必须自己安装。幸运的是,这很容易。最简单的入门方法之一是使用Sinatra。安装gem:geminstallsinatra然后创建myapp.rb:require'sinatr

  9. ruby - 创建一个临时文件而不在 Ruby 中打开它 - 2

    有没有办法在不打开临时文件的情况下创建它?我必须运行一个可执行文件,将它的输出重定向到一个文件,然后读取并解析它。tempfile创建的所有内容都已打开,这会触发错误,因为文件已锁定。 最佳答案 你也可以使用Dir::TmpnameDir::Tmpname.create('your_application_prefix'){|path|putspath}路径将包含唯一路径参见https://github.com/ruby/ruby/blob/ruby_1_9_3/lib/tmpdir.rb#L116

  10. ruby-on-rails - rails - x-sendfile + 临时文件 - 2

    前段时间我写了aquestion关于在Rails应用程序中使用临时文件。在特殊情况下,我决定使用tempfile如果我还想使用x-sendfile指令(asaparameterinRails2,orasaconfigurationoptioninRails3)以便文件发送由我的Web服务器直接处理,而不是我的Rails应用程序,这会导致问题。所以我想做这样的事情:require'tempfile'deffoo()#createsatemporaryfileintmp/Tempfile.open('prefix',"#{Rails.root}/tmp")do|f|f.print('ate

随机推荐