例如,如果我有一个像 172.20.10.0/24 这样的网络规范,“24”就是比特数。将其转换为像 0xffffff00 这样的网络掩码的最佳方法是什么?
9 回答
假设 32 位掩码和 32 位 int。
int keepBits = 24; /* actually get it from somewhere else? */
int mask = (0xffffffff >> (32 - keepBits )) << (32 - keepBits);
注意:这不一定是“获取接口的网络掩码的最佳方法是什么?”问题的答案。
我总是这样做(在你的情况下 cidr = 24):
uint32_t ipv4Netmask;
ipv4Netmask = 0xFFFFFFFF;
ipv4Netmask <<= 32 - cidr;
ipv4Netmask = htonl(ipv4Netmask);
这仅适用于 ipv4Netmask 实际上是 uint32_t,不要将其设为 int,因为 int 不必在每个系统上都是 32 位。结果被转换为网络字节顺序,这是大多数系统函数所期望的。
请注意,如果cidr
为零,则此代码将失败,因为该代码会将 32 位变量移动 32 位,不管你信不信,这是 C 中未定义的行为。人们期望结果始终为零,但 C 标准说这不是一开始就定义的。如果您的 CIDR 可以为零(仅允许在任何 IP 地址占位符 0.0.0.0/0 中使用),则代码必须捕获特殊情况。
这不是一个编程问题,但在 linux 中你可以使用 whatmask。
whatmask 72.20.10.0/24
返回
IP Entered = ..................: 72.20.10.0
CIDR = ........................: /24
Netmask = .....................: 255.255.255.0
Netmask (hex) = ...............: 0xffffff00
Wildcard Bits = ...............: 0.0.0.255
------------------------------------------------
Network Address = .............: 72.20.10.0
Broadcast Address = ...........: 72.20.10.255
Usable IP Addresses = .........: 254
First Usable IP Address = .....: 72.20.10.1
Last Usable IP Address = ......: 72.20.10.254
int keepbits = 24;
int mask = keepbits > 0 ? 0x00 - (1<<(32 - keepbits)) : 0xFFFFFFFF;
为什么要在减法或三元语句上浪费时间?
int suffix = 24;
int mask = 0xffffffff ^ 0xffffffff >> suffix;
如果您知道您的整数正好是 32 位长,那么您只需要输入 0xffffffff 一次。
int32_t mask = ~(0xffffffff >> suffix);
两者都编译成完全相同的汇编代码。
这是VBScript,FWIW中的解决方案
option explicit
'whatmask 72.20.10.0/24
If WScript.Arguments.Unnamed.Count < 1 Then
WScript.Echo "WhatMask xxx.xxx.xxx.xxx/xx"
Wscript.Quit
End If
Dim sToFind
Dim aParts
Dim nSubnet
sToFind = WScript.Arguments(0)
aParts = Split( sToFind, "/", 2 )
nSubnet = aParts(1)
if nSubnet < 1 or nSubnet > 32 then
WScript.echo "Subnet out of range [1..32]"
Wscript.quit
end if
Dim sBinary
sBinary = String( nSubnet, "1")
sBinary = sBinary & String( 32 - nSubnet, "0" )
wscript.echo "0x" & lcase( binary2hexadecimal( sBinary ) )
function binary2hexadecimal( sBin )
dim sSlice
dim sResult
dim i
for i = 1 to len( sBin ) step 4
sSlice = mid( sBin, i, 4 )
sResult = sResult & hex( binary2decimal( sSlice ) )
next
binary2hexadecimal = sResult
end function
function binary2decimal( sFourbits )
dim i
dim bit
dim nResult
nResult = 0
for i = 4 to 1 step -1
bit = mid(sFourbits, i, 1 )
nResult = nResult * 2 + bit
next
binary2decimal = nResult
end function
从命令行
>whatmask.vbs 123.12.123.17/23
0xfffff700
将先前的答案与以下代码一起使用时要小心:
0xFFFFFFFF << 32 - cidr
或者
-1 << 32 - cidr
至少在 C# 中,它将首先用 0x1F 屏蔽移位计数。因此,对于前缀为 0 的 cidr(即整个 IPv4 地址范围):
int cidr=0;
0xFFFFFFFF << (32 - cidr) == 0xFFFFFFFF
这不是你想要的。相反,您应该使用:
int cidr=0;
(int)(0xFFFFFFFFL << (32 - cidr)) == 0
您可以尝试一些简单的方法,例如获取位数并除以 4。这会给您掩码中的前导 F。然后取余数并从 0 位切换到 3 位。
/* C# version merging some of the other contributions and corrected for byte order. */
int cidr = 24;
var ipv4Netmask = 0xFFFFFFFF;
ipv4Netmask <<= 32 - cidr;
byte[] bytes = BitConverter.GetBytes(ipv4Netmask);
Array.Reverse(bytes);
ipv4Netmask = BitConverter.ToUInt32(bytes, 0);
// mask is now ready for use such as:
var netmask = new IPAddress(ipv4Netmask);