我必须将 IP 地址分类,这样我就可以在防火墙中阻止整个类。当我尝试对 /24 类进行操作时,它工作得很好,但当对 /16 类进行操作时,效果不太好。我在 txt 文件中有一个 IP 列表,我想从中排序
for IPBL in `cat /tmp/IPs`; do
CT=`grep -c ${IPBL%.[0-9]*} /tmp/IPs`
if [ "$CT" -gt "10" ]; then
echo "$IPBL ${IPBL%.[0-9]*}.0/24 $CT" >>/tmp/spam.lst
fi
done
cat /tmp/spam.lst |sort -n
所以这工作正常并打印出所有超过 10 个匹配的 ip 都是 C 类。
for IPBL in `cat /tmp/IPs`; do
CT=`grep -c ${IPBL%.[0-9]*.[0-9]*} /tmp/IPs`
if [ "$CT" -gt "10" ]; then
echo "$IPBL ${IPBL%.[0-9]*.[0-9]*}.0.0/16 $CT" >>/tmp/spam.lst
fi
done
cat /tmp/spam.lst |sort -n
因此,在这个例子中,大多数匹配都可以,但有些会grep
更多,例如。
- ip
8.6.X.X
会匹配18.6.X.X
,168.6.X.X
等等。
我尝试放置^${IPBL%.[0-9]*.[0-9]*}
在grep
匹配行的开头,但没有帮助,也没有
grep -E -c "${IPBL%.[0-9]{1,3}.[0-9]{1,3}}" /tmp/IPs
在 ip 数字中匹配特定的数字位数,并且不要放在^
字符串前面。
提取精确匹配的最有效方法是什么?
文件 /tmp/IPs 很大,但是执行 B mask grep 会匹配以下所有 IP 编号。正确的是只有 1 个匹配项(第 2 行)。
#IPBL=8.6.144.6
#grep ${IPBL%.[0-9]*.[0-9]*} /tmp/IPs
5.188.62.76
8.6.144.6
39.48.63.128
49.178.61.44
68.61.98.98
73.121.228.65
78.128.60.44
81.68.68.194
86.185.248.61
103.129.178.69
108.61.115.213
108.61.199.100
138.68.224.206
138.68.235.36
142.4.218.69
148.63.196.97
148.64.121.254
148.66.129.250
148.66.130.114
149.202.8.66
173.228.198.65
174.251.128.60
176.78.65.246
176.9.208.67
178.128.68.121
178.62.67.41
178.63.146.46
212.48.66.224
答案1
如果我理解正确的话,您想要解析 IP 列表并确定它们属于哪个 B 类或 C 类网络。如果任何此类网络出现超过 10 次,您需要在注释中打印 IP 及其所属网络
A.B.C.D A.B.0.0/16 n
或者
A.B.C.D A.B.C.0/24 n
分别写入输出文件spam.lst
,其中n
是相应子网的实际出现次数。
我为该任务提出以下awk
程序(我们称之为sort.awk
):
#!/bin/awk -f
BEGIN{
FS=OFS="."
}
NF==4{
if (FNR==NR) {
NF=cl
count[$0]++
next
}
for (n in count) {
if (index($0,n)==1) {
if (count[n]<=th) next
printf "%s %s",$0,n
for (i=cl;i<4;i++) printf ".0"
printf "/%d %d\n",8*cl,count[n]
}
}
}
您可以这样称呼它:
awk -v cl=2 -v th=1 -f sort.awk ips.txt ips.txt> spam.lst
请注意,输入文件被处理两次,因此作为awk
! 的参数出现两次。
该程序的工作原理如下:
- 您可以将 CIDR 网络类别指定为B 类网络或C 类网络的
awk
变量。cl
2
3
- 您可以将要阻止整个子网的最小出现次数指定为
awk
变量th
。 - 该程序将输入和输出分隔符设置为
.
将输入行拆分为字段.
。 - 该脚本仅考虑包含 4 个字段的行(IP 的最低健全性检查)
- 在第一遍中(
FNR
每个文件行计数器 等于NR
全局行计数器),我们注册遇到的子网。对于每一行,字段编号被截断为 in 中的值,cl
以将其截断为 B 类或 C 类网络“基地址”。然后,数组中这个(新生成的)基地址的计数器count
增加,并且处理跳到下一行。 - 在第二遍中,我们迭代所有指数的
count
(即在第一遍中注册的所有子网)以查看当前行上的IP是否以该子网地址开头。如果关联计数大于阈值,我们输出当前 IP 地址,然后输出基地址,并在右侧填充 和.0
并附加 CIDR 表示法中的网络掩码,最后输出出现计数。
的输出cl=2
以及th=1
您显示的示例 IP 列表如下所示
108.61.115.213 108.61.0.0/16 2
108.61.199.100 108.61.0.0/16 2
138.68.224.206 138.68.0.0/16 2
138.68.235.36 138.68.0.0/16 2
148.66.129.250 148.66.0.0/16 2
148.66.130.114 148.66.0.0/16 2
最初的提议是为了整合到现有的脚本中,如下所示:
awk -v cl=2 -v nw="8.6.0.0" -F'.' 'BEGIN{split(nw,ref,/\./)} NF==4{for (i=1;i<=cl;i++) {if ($i!=ref[i]) next} printf "%s %s/%d\n",$0,nw,8*cl}' ips.txt
在这里,我们将解析 IP 列表,以检查它们是否与通过awk
变量指定的给定网络基地址属于同一网络nw
。
- 一开始,参考网络基础IP按字段拆分成一个数组
ref
。 - 对于遇到的每一行,程序首先检查它是否包含 4 个字段(IP 的最低健全性检查)。如果是,它会比较
cl
当前行和参考 IP 的第一个字段。如果其中任何一个不匹配,则跳过该行并继续处理下一行。如果所有相关字段都匹配,则打印 IP,然后打印 CIDR 表示法的网络。
答案2
根据最初的问题,我设法更新 grep 语句以获得想要的结果,对于任何对仅 bash 解决方案感兴趣的人来说,更新的代码部分如下所示:
for IPBL in `cat /tmp/IPs`; do
CT=`grep -c "^${IPBL%.[0-9]*.[0-9]*}\." /tmp/IPs`
if [ "$CT" -gt "10" ]; then
echo "$IPBL ${IPBL%.[0-9]*.[0-9]*}.0.0/16 $CT" >>/tmp/spam.lst
fi
done
cat /tmp/spam.lst |sort -n
更改了 grep 的参数^
- 从行的开头开始,并\.
在 ip 地址中的第二个数字后添加一个点,从而给出特定 B 类 IP 范围的精确匹配:
"^${IPBL%.[0-9]*.[0-9]*}\."
现在 ip 8.6.144.6 在 IPs 文件中只有一个匹配项,因此不会显示在输出中,但一个 B 类匹配项将如下所示:
3.8.35.118 3.8.0.0/16 12
3.8.36.119 3.8.0.0/16 12
3.8.36.121 3.8.0.0/16 12
3.8.37.124 3.8.0.0/16 12
3.8.37.125 3.8.0.0/16 12
3.8.37.126 3.8.0.0/16 12
3.8.37.94 3.8.0.0/16 12
3.8.37.96 3.8.0.0/16 12
3.8.37.97 3.8.0.0/16 12
3.8.37.97 3.8.0.0/16 12
3.8.37.98 3.8.0.0/16 12
3.8.37.98 3.8.0.0/16 12