判断两个IP是否在同一网段
判断脚本
原理
ip和掩码做与计算。如果结果相同,则证明两个ip在同一个网段
#!/bin/bash
IPPattern='^(\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>\.){3}\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>$'
function check_ip_valide()
{
IP="$1"
for special_ip in ${special_ips[@]}
do
local ret=$(echo $IP | grep ${special_ip})
if [ -n "$ret" ];then
return 1
fi
done
if [[ "${IP}" =~ ${IPPattern} ]]; then
return 0
else
return 1
fi
}
function calc_ip_net()
{
sip="$1"
snetmask="$2"
check_ip_valide "$sip"
if [ $? -ne 0 ];then echo "";return 1;fi
local ipFIELD1=$(echo "$sip" |cut -d. -f1)
local ipFIELD2=$(echo "$sip" |cut -d. -f2)
local ipFIELD3=$(echo "$sip" |cut -d. -f3)
local ipFIELD4=$(echo "$sip" |cut -d. -f4)
local netmaskFIELD1=$(echo "$snetmask" |cut -d. -f1)
local netmaskFIELD2=$(echo "$snetmask" |cut -d. -f2)
local netmaskFIELD3=$(echo "$snetmask" |cut -d. -f3)
local netmaskFIELD4=$(echo "$snetmask" |cut -d. -f4)
local tmpret1=$[$ipFIELD1&$netmaskFIELD1]
local tmpret2=$[$ipFIELD2&$netmaskFIELD2]
local tmpret3=$[$ipFIELD3&$netmaskFIELD3]
local tmpret4=$[$ipFIELD4&$netmaskFIELD4]
echo "$tmpret1.$tmpret2.$tmpret3.$tmpret4"
}
tmpip1=$(calc_ip_net "$1" "$3")
tmpip2=$(calc_ip_net "$2" "$3")
if [ "$tmpip1" != "$tmpip2" ];then
echo "no"
else
echo "same"
fi
实验结果
判断IP地址是否在某一个ip段内
方法1:利用(依赖)ipcalc
#!/bin/bash
IP=$1
if [ -z $IP ]
then
echo -e "\e[31;42m sh ipcalc.sh IP \e[0m"
exit
fi
while read MASK
do
max=`/usr/bin/ipcalc -mbn $MASK|grep 'BROADCAST='|awk -F 'BROADCAST=' '{print $2}'`
min=`/usr/bin/ipcalc -mbn $MASK|grep 'NETWORK='|awk -F 'NETWORK=' '{print $2}'`
MIN=`echo $min|awk -F"." '{printf"%.0f\n",$1*256*256*256+$2*256*256+$3*256+$4}'`
MAX=`echo $max|awk -F"." '{printf"%.0f\n",$1*256*256*256+$2*256*256+$3*256+$4}'`
IPvalue=`echo $IP|awk -F"." '{printf"%.0f\n",$1*256*256*256+$2*256*256+$3*256+$4}'`
if [ "$IPvalue" -ge "$MIN" ] && [ "$IPvalue" -le "$MAX" ]
then
echo "$IP"
exit
fi
done</etc/zabbix/zabbix_agentd.d/ipset.conf
cat > /usr/local/bin/judge_ip << 'EOF'
#!/bin/bash
MASK=$2
IP=$1
max=`/usr/bin/ipcalc -mbn $MASK|grep 'BROADCAST='|awk -F 'BROADCAST=' '{print $2}'`
min=`/usr/bin/ipcalc -mbn $MASK|grep 'NETWORK='|awk -F 'NETWORK=' '{print $2}'`
MIN=`echo $min|awk -F"." '{printf"%.0f\n",$1*256*256*256+$2*256*256+$3*256+$4}'`
MAX=`echo $max|awk -F"." '{printf"%.0f\n",$1*256*256*256+$2*256*256+$3*256+$4}'`
IPvalue=`echo $IP|awk -F"." '{printf"%.0f\n",$1*256*256*256+$2*256*256+$3*256+$4}'`
if [ "$IPvalue" -ge "$MIN" ] && [ "$IPvalue" -le "$MAX" ]
then
echo "$IP"
exit
fi
EOF
chmod 777 /usr/local/bin/judge_ip
judge_ip 192.168.10.11 192.168.10.0/24
方法2:
方法1中用ipcalc计算出 网络地址(min)和广播地址(max),但是由于某些机器上没有安装有ipcalc,所以可以用下面《IP网络地址和广播地址计算》章节的方法计算出min和max。
IP网络地址和广播地址计算
#!/bin/bash
IPPattern="(\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>\.){3}\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>"
maskPattern="[1-9]|[12][0-9]|3[01]"
while :
do
echo -e -n "Please input a legal IP address [such as 192.168.1.1/16]: "
read userInput
IPMask=`echo $userInput | egrep "$IPPattern/$maskPattern"`
#Such as 192.168.1.1/24
if [ -z "$IPMask" ] ;then
echo "Please input the right format. [such as 192.168.1.1/1-31] "
continue
fi
IPAddr=`echo $IPMask | cut -d/ -f1`
IPType[1]=`echo $IPAddr | cut -d. -f1`
IPType[2]=`echo $IPAddr | cut -d. -f2`
IPType[3]=`echo $IPAddr | cut -d. -f3`
IPType[4]=`echo $IPAddr | cut -d. -f4`
mask=`echo $IPMask | cut -d/ -f2`
echo "IP address is ${IPType[1]}*${IPType[2]}*${IPType[3]}*${IPType[4]} , Mask is $mask ."
((IPHex[1]=IPType[1]<<24))
((IPHex[2]=IPType[2]<<16))
((IPHex[3]=IPType[3]<<8))
((IPHex[4]=IPType[4]))
#192 c0 ; 1 1 1
((iph=${IPHex[1]}+${IPHex[2]}+${IPHex[3]}+${IPHex[4]}))
#echo $iph
#0xffffffff
#declare -i strMask1=4294967295
declare -i strMask1=0xffffffff
#echo $strMask1
((strMask1=strMask1<<(32-mask) & 0xffffffff))
#echo $strMask1
((strMask2=~strMask1))
#echo $strMask2
((networkAddr=iph & strMask1))
((bcastAddr= (iph | strMask2) & 0xffffffff))
#echo $networkAddr | awk '{printf "%x\n",$0}'
#echo $bcastAddr | awk '{printf "%x\n",$0}'
((IPHex[1]=networkAddr>>24 & 0x000000ff))
((IPHex[2]=networkAddr>>16 & 0x000000ff))
((IPHex[3]=networkAddr>>8 & 0x000000ff))
((IPHex[4]=networkAddr & 0x000000ff))
echo -e "Network Address : ${IPHex[1]}.${IPHex[2]}.${IPHex[3]}.${IPHex[4]}"
((IPHex[1]=bcastAddr>>24 & 0x000000ff))
((IPHex[2]=bcastAddr>>16 & 0x000000ff))
((IPHex[3]=bcastAddr>>8 & 0x000000ff))
((IPHex[4]=bcastAddr & 0x000000ff))
echo -e "Broadcast Address : ${IPHex[1]}.${IPHex[2]}.${IPHex[3]}.${IPHex[4]}"
done
判断两个网段是否存在包含与被包含的关系
设定两个网段:net1是192.168.10.0/24,net2是192.168.10.128/25。使用Shell脚本,判断是net1包含net2还是net2包含net1. 解题思路:
将两个网段全部转换为二进制,且不带字段分隔符(即点号),取网络位。如果在net1的二进制字符串里面截取到了net2的二进制字符串,则net2包含net1.
#!/bin/bash
net1="192.168.10.0/24"
net2="192.168.10.128/25"
netID1D="`echo $net1 | cut -d "/" -f 1`"
netID2D="`echo $net2 | cut -d "/" -f 1`"
mask1="`echo $net1 | cut -d "/" -f 2`"
mask2="`echo $net2 | cut -d "/" -f 2`"
array1D[0]="`echo $netID1D | awk -v FS="." '{print $1}'`"
array1D[1]="`echo $netID1D | awk -v FS="." '{print $2}'`"
array1D[2]="`echo $netID1D | awk -v FS="." '{print $3}'`"
array1D[3]="`echo $netID1D | awk -v FS="." '{print $4}'`"
array2D[0]="`echo $netID2D | awk -v FS="." '{print $1}'`"
array2D[1]="`echo $netID2D | awk -v FS="." '{print $2}'`"
array2D[2]="`echo $netID2D | awk -v FS="." '{print $3}'`"
array2D[3]="`echo $netID2D | awk -v FS="." '{print $4}'`"
array1B[0]="`echo "obase=2;${array1D[0]}" | bc`"
array1B[1]="`echo "obase=2;${array1D[1]}" | bc`"
array1B[2]="`echo "obase=2;${array1D[2]}" | bc`"
array1B[3]="`echo "obase=2;${array1D[3]}" | bc`"
array2B[0]="`echo "obase=2;${array2D[0]}" | bc`"
array2B[1]="`echo "obase=2;${array2D[1]}" | bc`"
array2B[2]="`echo "obase=2;${array2D[2]}" | bc`"
array2B[3]="`echo "obase=2;${array2D[3]}" | bc`"
zeroArray=(0 0 00 000 0000 00000 000000 0000000)
for ((i=0;i<${#array1B[$i]};i++))
do
zeroNum=$((8 - ${#array1B[$i]}))
if [ $zeroNum -gt 0 ]
then
testStr="`awk -v zero="${zeroArray[$zeroNum]}" -v rawStr="${array1B[$i]}" 'BEGIN {printf "%s%s",zero,rawStr}'`"
array1B[$i]=$testStr
fi
done
for ((i=0;i<${#array2B[$i]};i++))
do
zeroNum=$((8 - ${#array2B[$i]}))
if [ $zeroNum -gt 0 ]
then
testStr="`awk -v zero="${zeroArray[$zeroNum]}" -v rawStr="${array2B[$i]}" 'BEGIN {printf "%s%s",zero,rawStr}'`"
array2B[$i]=$testStr
fi
done
netID1B=${array1B[0]}${array1B[1]}${array1B[2]}${array1B[3]}
netID2B=${array2B[0]}${array2B[1]}${array2B[2]}${array2B[3]}
netID1BNo0="`awk -v inNet="$netID1B" -v inMask="$mask1" 'BEGIN {print substr(inNet,1,inMask)}'`"
netID2BNo0="`awk -v inNet="$netID2B" -v inMask="$mask2" 'BEGIN {print substr(inNet,1,inMask)}'`"
echo -e "net1十进制为:$net1\tnet1二进制为:$netID1BNo0"
echo -e "net2十进制为:$net2\tnet2二进制位:$netID2BNo0"
netVS1="`awk -v inNet1="$netID1BNo0" -v inNet2="$netID2BNo0" 'BEGIN {print index(inNet1,inNet2)}'`"
netVS2="`awk -v inNet2="$netID1BNo0" -v inNet1="$netID2BNo0" 'BEGIN {print index(inNet1,inNet2)}'`"
if [ $netVS1 -ne 0 ]
then
echo "计算结果:$net2 包含 $net1"
fi
if [ $netVS2 -ne 0 ]
then
echo "计算结果:$net1 包含 $net2"
fi
运行结果
[root@localhost ~]# sh netCal.sh
net1十进制为:192.168.10.0/24 net1二进制为:110000001010100000001010
net2十进制为:192.168.10.128/25 net2二进制位:1100000010101000000010101
计算结果:192.168.10.0/24 包含 192.168.10.128/25
计算可用IP地址范围
输入: 输入IP网段,格式: xx.xx.xx.xx/[0-32]
输出:可用地址范围
思路:
ip与掩码拆分,健壮性判断
按位与,或者主机位置0,求出网络号
计算该网段可用地址范围。
效果:
[root@centos8 commonshells]# ./calIpRange.sh 114.12.3.3/30
114.12.3.3/30该网段网络号为114.12.3.0
114.12.3.3/30该网段最小可用地址为114.12.3.1
114.12.3.3/30该网段最大可用地址为114.12.3.2
114.12.3.3/30该网段广播地址为114.12.3.3
————————————————
脚本:
#!/bin/bash
#########################################################
#Filename: calIpRange.sh
# Author: LiangDong
# Email: 395539184@
# Date: 2021-04-04
# URL: https:///ledrsnet
# Desc: 输入IP网段,输出可用地址范围
# 1.ip与掩码拆分,健壮性判断
# 2.按位与,求出网络号
# 3.计算该网段可用地址范围。
#
#########################################################
set -eu
# 1.ip掩码拆分并进行健壮性判断
E_NOARGS=65
if [ -z "$1" ];then
echo "Usage:`basename $0` ip/mask"
exit $E_NOARGS
fi
IP_MASK=$1
IP=`echo $IP_MASK |sed -En 's/^(.*)\/([0-9]{1,2})/\1/p'`
NET_MASK=`echo $IP_MASK |sed -En 's/^(.*)\/([0-9]{1,2})/\2/p'`
#echo IP_MASK=$IP_MASK
#echo IP=$IP
#echo NET_MASK=$NET_MASK
if [[ ! $IP =~ ^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]];then
echo "Ip address $IP is invalid . Useage: ip/mask"
exit 2
elif [ $NET_MASK -gt 32 -o $NET_MASK -lt 0 ];then
echo "netmask should be in 0-32,your input netmask is $NET_MASK; Useage: ip/mask"
exit 3
elif [ $NET_MASK -eq 32 ];then
echo "主机位是32位,可用地址为$IP"
exit 4
fi
# 2.求出ip第几段前几位作运算
IP_SUB1=`echo $IP |cut -d. -f1`
IP_SUB2=`echo $IP |cut -d. -f2`
IP_SUB3=`echo $IP |cut -d. -f3`
#IP_SUB4=`echo $IP |cut -d. -f4`
#IP_INDEX=`[ $[$NET_MASK/8+1] -ge 5 ] && echo 4 || echo $[$NET_MASK/8+1]`
#echo IP_INDEX=$IP_INDEX
#eval echo \$IP_SUB$IP_INDEX
IP_INDEX=`echo $[$NET_MASK/8+1]`
IP_SUB=`echo $IP |cut -d. -f$IP_INDEX`
IP_SUB_BINARY=`echo "obase=2;$IP_SUB" |bc |xargs printf "%08d"`
#echo IP_INDEX=$IP_INDEX
#echo IP_SUB=$IP_SUB
#echo IP_SUB_BINARY=$IP_SUB_BINARY
IP_SUB_NET_BIT=$[$NET_MASK%8]
IP_SUB_HOST_BIT=$[8-$NET_MASK%8]
#echo IP_SUB_NET_BIT=$IP_SUB_NET_BIT
#echo IP_SUB_HOST_BIT=$IP_SUB_HOST_BIT
# 3.网络位不变,主机位全为0
AVAILABLE_MIN_IP=$(echo $IP_SUB_BINARY|head -c${IP_SUB_NET_BIT} |xargs printf "ibase=2;%s`echo 00000000 |head -c${IP_SUB_HOST_BIT}`\n"|bc)
#echo AVAILABLE_MIN_IP=$AVAILABLE_MIN_IP
# 与操作 生成连续重复的字符串有什么好办法没?
#R_NET_MASK=
#R_HOST_MASK=
#R_MASK=
#for i in `seq ${IP_SUB_NET_BIT}`;do
# R_NET_MASK+=1
#done
#for i in `seq ${IP_SUB_HOST_BIT}`;do
# R_HOST_MASK+=0
#done
#R_MASK=`echo "ibase=2;$R_NET_MASK$R_HOST_MASK"|bc`
#echo R_MASK=$R_MASK
#A_MIN_IP=$[$IP_SUB&$R_MASK]
#echo A_MIN_IP=$A_MIN_IP
# 网络位不变,主机位全为1
AVAILABLE_MAX_IP=$(echo $IP_SUB_BINARY|head -c${IP_SUB_NET_BIT} |xargs printf "ibase=2;%s`echo 11111111 |head -c${IP_SUB_HOST_BIT}`\n"|bc)
#echo AVAILABLE_MAX_IP=$AVAILABLE_MAX_IP
# 4.输出可用地址范围
case $IP_INDEX in
1)
echo "$IP_MASK该网段网络号为${AVAILABLE_MIN_IP}.0.0.0"
echo "$IP_MASK该网段最小可用地址为${AVAILABLE_MIN_IP}.0.0.1"
echo "$IP_MASK该网段最大可用地址为${AVAILABLE_MAX_IP}.255.255.254"
echo "$IP_MASK该网段广播地址为${AVAILABLE_MAX_IP}.255.255.255"
;;
2)
echo "$IP_MASK该网段网络号为${IP_SUB1}.${AVAILABLE_MIN_IP}.0.0"
echo "$IP_MASK该网段最小可用地址为${IP_SUB1}.${AVAILABLE_MIN_IP}.0.1"
echo "$IP_MASK该网段最大可用地址为${IP_SUB1}.${AVAILABLE_MAX_IP}.255.254"
echo "$IP_MASK该网段广播地址为${IP_SUB1}.${AVAILABLE_MAX_IP}.255.255"
;;
3)
echo "$IP_MASK该网段网络号为${IP_SUB1}.${IP_SUB2}.${AVAILABLE_MIN_IP}.0"
echo "$IP_MASK该网段最小可用地址为${IP_SUB1}.${IP_SUB2}.${AVAILABLE_MIN_IP}.1"
echo "$IP_MASK该网段最大可用地址为${IP_SUB1}.${IP_SUB2}.${AVAILABLE_MAX_IP}.254"
echo "$IP_MASK该网段广播地址为${IP_SUB1}.${IP_SUB2}.${AVAILABLE_MAX_IP}.255"
;;
4)
echo "$IP_MASK该网段网络号为${IP_SUB1}.${IP_SUB2}.${IP_SUB3}.${AVAILABLE_MIN_IP}"
echo "$IP_MASK该网段最小可用地址为${IP_SUB1}.${IP_SUB2}.${IP_SUB3}.$[${AVAILABLE_MIN_IP}+1]"
echo "$IP_MASK该网段最大可用地址为${IP_SUB1}.${IP_SUB2}.${IP_SUB3}.$[${AVAILABLE_MAX_IP}-1]"
echo "$IP_MASK该网段广播地址为${IP_SUB1}.${IP_SUB2}.${IP_SUB3}.${AVAILABLE_MAX_IP}"
;;
*)
echo "Calculator Error Exception!"
esac
附录:
如何判断两个IP是否在同一网段原理
如何判断两个IP是否在同一网段
下来举例说明,如何去判断A和B两个IP是否在同一网段。
A IP:202.194.128.9 B IP:202.194.128.14 子网掩码:255.255.255.0
1.把A和B的地址转换为二进制的
A:1100 1010.1100 0010.1000 0000.0000 1001 B:1100 1010.1100 0010.1000 0000.0000 1101 掩码 :1111 1111.1111 1111. 1111 1111 .0000 0000
2、要判断两个IP是否在同一网段,主要是看看他们的网络标识是否一样,其实一个IP的网络标识也就是他的IP和子网掩码AND之后的结——比如上面两个AND以后的结果如下:
A:11001010.1100 0010.1000 0000 .0000 0000 转化为十进制:202.194.128.0 B:1100 1010.1100 0010.1000 0000.0000 0000 转化为十进制:202.194.128.0
这说明两个IP的网络标识相同,也就是说他们在同一子网。
3、有的时候我们还想知道,两个IP各自的主机标识,先将子网掩码取反,再和IP做AND.
A:1100 1010.1100 0010.1000 0000.0000 1001 B:1100 1010.1100 0010.1000 0000.0000 1101 掩码取反:0000 0000.0000 0000.0000 0000.1111 1111
AND 之后结果:
A:0000 0000.0000 0000.0000 0000.0000 1001 转化为十进制:9 B:0000 0000.0000 0000.0000 0000.0000 1101 转化为十进制:14
也就是说A和B的主机标识为9和14
计算PREFIX数值
计算掩码PREFIX数值
255.255.255.192--->11111111.11111111.11111111.1100000-→26个bit.---》PREFIX=26
255.255.255.0--->11111111.11111111.11111111.0000000--->24个bit.---》PREFIX=24
还有更简单的:
执行 ip addr ,对于的IP 就自己显示PREFIX:
ipcalc命令 – 简单的IP地址计算器
[root@ezdcc ~]# ipcalc -p 192.168.88.56 255.255.255.0 PREFIX=24 [root@ezdcc ~]# ipcalc -n 192.168.88.56 255.255.255.0 NETWORK=192.168.88.0
[root@ezdcc ~]# ipcalc -m -b -n 119.29.29.29/28 NETMASK=255.255.255.240 BROADCAST=119.29.29.31 NETWORK=119.29.29.16
语法格式: ipcalc [参数] [IP地址]
常用参数:
-b | 由给定的IP地址和网络掩码计算出广播地址 |
-h | 显示给定IP地址所对应的主机名 |
-m | 由给定的IP地址计算器网络掩码 |
-p | 显示给定的掩码或IP地址的前缀 |
-n | 由给定的IP地址和网络掩码计算网络地址 |
-s | 安静模式,不显示任何错误信息 |
--help | 显示帮助信息 |
IP 转网口
ifconfig|grep -w "100.96.192.13" -B 1|head -n 1|awk -F ":" '{print $1}'
提取IP地址
grep -oE '((1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])' messages
如果有
GNU sed
,您只需添加-r
标志即可使用ERE:sed -rn '/((1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])/p' file
否则,您将需要转义某些字符:
sed -n '/\(\(1\?[0-9][0-9]\?\|2[0-4][0-9]\|25[0-5]\)\.\)\{3\}\(1\?[0-9][0-9]\?\|2[0-4][0-9]\|25[0-5]\)/p' file
这些字符包括:
- 使用括号的组:
(
,)
- 发生支撑:
{
,}
- '或'管道:
|
- 非贪婪的问号:
?
通常(虽然不适合您的情况)我使用以下内容来匹配IP地址:
sed -rn '/([0-9]{1,3}\.){3}[0-9]{1,3}/p' file
或者在兼容模式下:
sed -n '/\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}/p' file