今天有一个需求,要验证用户的输入ip 和 某一个环境下的ip/mask是否在同一个网段,准确的说 ip/mask表述的不准确,权威的表述是这个:Classless Inter-Domain Routing
比如用户填的是: 10.1.1.5
server端返回的ip/mask是这个10.1.1.12/24
我们先解决这个问题,我们都知道,本来ip地址是32位的二进制数来表示。为了方便我们将分成4个字节,每个字节8位,转换成十进制来显示。
10.1.1.5 转换成二进制是这样:
00001010 00000001 00000001 00000101
10.1.1.12 转换成二进制是这样:
00001010 00000001 00000001 00001100
判断是否在同一个网段的要求就是我们那这两个ip地址,与子网掩码做一次 & 与运算,然后判断结果是否是相等,相等则是属于同一网段。
10.1.1.12/24
后面这个24则标识了子网掩码(ipv4 max value is 32,ipv6 max value is 128):
11111111 11111111 11111111 00000000(32位,前24位为1)
我们需要对
00001010 00000001 00000001 00000101 (10.1.1.5)
与掩码
11111111 11111111 11111111 00000000
做一次 & 操作;
然后对
00001010 00000001 00000001 00001100 (10.1.1.12)
与掩码
11111111 11111111 11111111 00000000
做一次 & 操作。
最后的结果是一样,属于同一网段。
帮助方法:
export const checkIsInSameNetworkSegment= (ip, ipMask)=> {
let arr = ipMask.split('/'),
mask = arr[1],
standardIp = arr[0]
mask = (0XFFFFFFFF)<<(32- Number(arr[1]))
let ips = ip.split('.').map(item=>parseInt(item)) //将ip分成4个数字组成的数组
let crdIps = standardIp.split('.').map(item=>parseInt(item)) //将ip分成4个数字组成的数组
let ipBinary = (ips[0]<<24) | (ips[1]<<16) | (ips[2]<<8) | (ips[3])
let crdIpBinary = (crdIps[0]<<24) | (crdIps[1]<<16) | (crdIps[2]<<8) | (crdIps[3])
return (ipBinary & mask) === (crdIpBinary & mask)
}
如果忘记了位运算请看这里: javascript位运算
其他资料: