#!/bin/bash
MAXCDN_ARRAY="108.161.176.0/20 94.46.144.0/20 146.88.128.0/20 198.232.124.0/22 23.111.8.0/22 217.22.28.0/22 64.125.76.64/27 64.125.76.96/27 64.125.78.96/27 64.125.78.192/27 64.125.78.224/27 64.125.102.32/27 64.125.102.64/27 64.125.102.96/27 94.31.27.64/27 94.31.33.128/27 94.31.33.160/27 94.31.33.192/27 94.31.56.160/27 177.54.148.0/24 185.18.207.65/26 50.31.249.224/27 50.31.251.32/28 119.81.42.192/27 119.81.104.96/28 119.81.67.8/29 119.81.0.104/30 119.81.1.144/30 27.50.77.226/32 27.50.79.130/32 119.81.131.130/32 119.81.131.131/32 216.12.211.59/32 216.12.211.60/32 37.58.110.67/32 37.58.110.68/32 158.85.206.228/32 158.85.206.231/32 174.36.204.195/32 174.36.204.196/32"
$IP = 108.161.184.123
if [ $IP in $MAXCDN_ARRAY ];
then:
echo "$IP is in MAXCDN range"
else:
echo "$IP is not in MAXCDN range"
fi
Run Code Online (Sandbox Code Playgroud)
我有一个MAXCDN_ARRAY
用作白名单的 IP 列表。我想检查一个特定的 IP 地址是否在这个数组的范围内。
如何构建代码以便它可以比较数组中的所有 IP 并说出此列表范围内的特定 IP?
cas*_*cas 17
您可以使用grepcidr检查 IP 地址是否在 CIDR 网络列表中。
#! /bin/bash
NETWORKS="108.161.176.0/20 94.46.144.0/20 146.88.128.0/20 198.232.124.0/22
23.111.8.0/22 217.22.28.0/22 64.125.76.64/27 64.125.76.96/27
64.125.78.96/27 64.125.78.192/27 64.125.78.224/27 64.125.102.32/27
64.125.102.64/27 64.125.102.96/27 94.31.27.64/27 94.31.33.128/27
94.31.33.160/27 94.31.33.192/27 94.31.56.160/27 177.54.148.0/24
185.18.207.65/26 50.31.249.224/27 50.31.251.32/28 119.81.42.192/27
119.81.104.96/28 119.81.67.8/29 119.81.0.104/30 119.81.1.144/30
27.50.77.226/32 27.50.79.130/32 119.81.131.130/32 119.81.131.131/32
216.12.211.59/32 216.12.211.60/32 37.58.110.67/32 37.58.110.68/32
158.85.206.228/32 158.85.206.231/32 174.36.204.195/32
174.36.204.196/32"
for IP in 108.161.184.123 108.161.176.123 192.168.0.1 172.16.21.99; do
grepcidr "$NETWORKS" <(echo "$IP") >/dev/null && \
echo "$IP is in MAXCDN range" || \
echo "$IP is not in MAXCDN range"
done
Run Code Online (Sandbox Code Playgroud)
注意:grepcidr
期望它匹配的 IP 地址在文件中,而不仅仅是命令行上的参数。这就是我必须使用<(echo "$IP")
上面的原因。
输出:
108.161.184.123 is in MAXCDN range
108.161.176.123 is in MAXCDN range
192.168.0.1 is not in MAXCDN range
172.16.21.99 is not in MAXCDN range
Run Code Online (Sandbox Code Playgroud)
grepcidr
可用于多个发行版,包括 Debian:
Package: grepcidr
Version: 2.0-1
Description-en: Filter IP addresses matching IPv4 CIDR/network specification
grepcidr can be used to filter a list of IP addresses against one or
more Classless Inter-Domain Routing (CIDR) specifications, or
arbitrary networks specified by an address range. As with grep, there
are options to invert matching and load patterns from a file.
grepcidr is capable of comparing thousands or even millions of IPs
to networks with little memory usage and in reasonable computation
time.
.
grepcidr has endless uses in network software, including: mail
filtering and processing, network security, log analysis, and many
custom applications.
Homepage: http://www.pc-tools.net/unix/grepcidr/
Run Code Online (Sandbox Code Playgroud)
否则,来源可在上面的链接中找到。
另一种选择是使用许多库/模块中的一个来编写perl
或python
脚本,以使用这些语言操作和检查 IPv4 地址。
例如,perl
模块Data::Validate::IP
有一个is_innet_ipv4($ip, $network)
功能;Net::CIDR::Lite
有一个非常相似的$cidr->find($ip);
方法;并且Net::IPv4Addr
有一个ipv4_in_network()
功能。
python
有类似的库,包括ipy
、ipaddr
、 和ipcalc
等。
我意识到这是较旧的并且已经有一个公认的答案,但是这个解决方案利用了我为跨多个服务器的可移植性而编写的函数,该环境grepcidr
不是跨所有服务器的标准包。
评论应该澄清它在做什么。
#! /bin/bash
# Set DEBUG=1, in order to see it iterate through the calculations.
#DEBUG=1
MAXCDN_ARRAY="108.161.176.0/20 94.46.144.0/20 146.88.128.0/20 198.232.124.0/22 23.111.8.0/22 217.22.28.0/22 64.125.76.64/27 64.125.76.96/27 64.125.78.96/27 64.125.78.192/27 64.125.78.224/27 64.125.102.32/27 64.125.102.64/27 64.125.102.96/27 94.31.27.64/27 94.31.33.128/27 94.31.33.160/27 94.31.33.192/27 94.31.56.160/27 177.54.148.0/24 185.18.207.65/26 50.31.249.224/27 50.31.251.32/28 119.81.42.192/27 119.81.104.96/28 119.81.67.8/29 119.81.0.104/30 119.81.1.144/30 27.50.77.226/32 27.50.79.130/32 119.81.131.130/32 119.81.131.131/32 216.12.211.59/32 216.12.211.60/32 37.58.110.67/32 37.58.110.68/32 158.85.206.228/32 158.85.206.231/32 174.36.204.195/32 174.36.204.196/32"
IP=108.161.184.123
function in_subnet {
# Determine whether IP address is in the specified subnet.
#
# Args:
# sub: Subnet, in CIDR notation.
# ip: IP address to check.
#
# Returns:
# 1|0
#
local ip ip_a mask netmask sub sub_ip rval start end
# Define bitmask.
local readonly BITMASK=0xFFFFFFFF
# Set DEBUG status if not already defined in the script.
[[ "${DEBUG}" == "" ]] && DEBUG=0
# Read arguments.
IFS=/ read sub mask <<< "${1}"
IFS=. read -a sub_ip <<< "${sub}"
IFS=. read -a ip_a <<< "${2}"
# Calculate netmask.
netmask=$(($BITMASK<<$((32-$mask)) & $BITMASK))
# Determine address range.
start=0
for o in "${sub_ip[@]}"
do
start=$(($start<<8 | $o))
done
start=$(($start & $netmask))
end=$(($start | ~$netmask & $BITMASK))
# Convert IP address to 32-bit number.
ip=0
for o in "${ip_a[@]}"
do
ip=$(($ip<<8 | $o))
done
# Determine if IP in range.
(( $ip >= $start )) && (( $ip <= $end )) && rval=1 || rval=0
(( $DEBUG )) &&
printf "ip=0x%08X; start=0x%08X; end=0x%08X; in_subnet=%u\n" $ip $start $end $rval 1>&2
echo "${rval}"
}
for subnet in $MAXCDN_ARRAY
do
(( $(in_subnet $subnet $IP) )) &&
echo "${IP} is in ${subnet}" && break
done
Run Code Online (Sandbox Code Playgroud)