Ama*_*ith 0 linux bash shell netstat iptables
有没有更好的方法来重写此代码以获得增强的性能?
如果你要获得一堆IP,系统似乎就会挂起.
TMP_PREFIX='/tmp/synd'
TMP_FILE="mktemp $TMP_PREFIX.XXXXXXXX"
BANNED_IP_MAIL=`$TMP_FILE`
BANNED_IP_LIST=`$TMP_FILE`
echo "Banned the following ip addresses on `date`" > $BANNED_IP_MAIL
echo >> $BANNED_IP_MAIL
BAD_IP_LIST=`$TMP_FILE`
netstat -ntu | grep SYN_RECV | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr > $BAD_IP_LIST
cat $BAD_IP_LIST
if [ $KILL -eq 1 ]; then
IP_BAN_NOW=0
while read line; do
CURR_LINE_CONN=$(echo $line | cut -d" " -f1)
CURR_LINE_IP=$(echo $line | cut -d" " -f2)
if [ $CURR_LINE_CONN -lt $NO_OF_CONNECTIONS ]; then
break
fi
IGNORE_BAN=`grep -c $CURR_LINE_IP $IGNORE_IP_LIST`
if [ $IGNORE_BAN -ge 1 ]; then
continue
fi
IP_BAN_NOW=1
echo "$CURR_LINE_IP with $CURR_LINE_CONN SYN_RECV connections" >> $BANNED_IP_MAIL
echo $CURR_LINE_IP >> $BANNED_IP_LIST
echo $CURR_LINE_IP >> $IGNORE_IP_LIST
if [ $CSF_BAN -eq 1 ]; then
$CSF -d $CURR_LINE_IP
else
$IPT -I INPUT -s $CURR_LINE_IP -j DROP
fi
done < $BAD_IP_LIST
if [ $IP_BAN_NOW -eq 1 ]; then
dt=`date`
hn=`hostname`
if [ $EMAIL_TO != "" ]; then
cat $BANNED_IP_MAIL | mail -s "IP addresses banned on $dt $hn" $EMAIL_TO
fi
fi
fi
rm -f $TMP_PREFIX.*
Run Code Online (Sandbox Code Playgroud)
当然,有很多方法可以改进,但你应该试着弄清楚真正的瓶颈在哪里.(它可能是iptables,在这种情况下,您可能希望尝试在一次调用中执行所有表更新,而不是一次执行一次.但我只是在猜测.)
以下是一些建议; 我没有读完所有内容:
netstat -ntu | grep SYN_RECV | awk '{print $5}' | cut -d: -f1 |
sort | uniq -c | sort -nr > $BAD_IP_LIST
Run Code Online (Sandbox Code Playgroud)
如果您只对SYN_RECV状态的连接感兴趣,为什么要列出udp?无论如何,您使用三个实用程序(grep,awk和cut)来执行一个简单的面向行的操作.你可以在一个中完成所有操作,例如awk:
awk '$6 == "SYN_RECV" {print substr($5, 1, index($5, ":") - 1)}'
Run Code Online (Sandbox Code Playgroud)
事实上,你也可以在awk中进行统一和计数:
awk '$6 == "SYN_RECV" {++ip[substr($5, 1, index($5, ":") - 1)]} END{for (i in ip) print ip[i], i}'
Run Code Online (Sandbox Code Playgroud)
编辑:你也可以在这里过滤所需的数量:
awk '$6 == "SYN_RECV" {++ip[substr($5, 1, index($5, ":") - 1)]}
END {for (i in ip) if (ip[i] >= '$NO_OF_CONNECTIONS') print ip[i], i}'
Run Code Online (Sandbox Code Playgroud)
现在您只需输出IP地址,因为您不再需要在bash脚本中进行过滤.我不知道这是否比通过排序和uniq和再次排序更快,但它可能很好.
while read line; do
CURR_LINE_CONN=$(echo $line | cut -d" " -f1)
CURR_LINE_IP=$(echo $line | cut -d" " -f2)
if [ $CURR_LINE_CONN -lt $NO_OF_CONNECTIONS ]; then
break
fi
Run Code Online (Sandbox Code Playgroud)
你想从stdin中读取两个字段.你为什么不这样做:
while read CURR_LINE_CONN CURR_LINE_IP IGNORED &&
((CURR_LINE_CONN >= NO_OF_CONNECTIONS)); do
Run Code Online (Sandbox Code Playgroud)
这节省了两个子壳和两个切割调用.(读取内置的IGNORED只是偏执狂,因为awk只会输出两个字段.但这并不是好偏执,因为它会默默地忽略错误.)
编辑:如上所述,你也可以在这里摆脱测试.所以它只会是:
netstat -nt |
awk '$6 == "SYN_RECV" {++ip[substr($5, 1, index($5, ":") - 1)]}
END { for (i in ip)
if (ip[i] >= '$NO_OF_CONNECTIONS')
print ip[i], i}' | tee $BAD_IP_LIST
if ((KILL)); then
IP_BAN_NOW=0
while read IP IGNORED; do
Run Code Online (Sandbox Code Playgroud)
下一个:
IGNORE_BAN=`grep -c $CURR_LINE_IP $IGNORE_IP_LIST`
if [ $IGNORE_BAN -ge 1 ]; then
continue
fi
Run Code Online (Sandbox Code Playgroud)
grep -c使grep读取整个输入文件以获取计数; 你只想知道ip是否存在.你想要grep -q:
if $(grep -q -F -x $CURR_LINE_IP $IGNORE_IP_LIST); then continue; fi
Run Code Online (Sandbox Code Playgroud)
(-F告诉grep将模式解释为字符串而不是正则表达式,这是你想要的,因为否则.是通配符.-x告诉grep匹配整行.一个ip可能是前缀或后缀甚至是中缀另一个会导致错误匹配.-F和-x的组合也可能更快一些,因为grep可以在很大程度上优化匹配.)
可能还有更多.就我而言.