安全标准的方式检查IP地址是否在范围/子网内

7

我有一小段代码,将32位无符号整数(即:uint32_t)转换为四个8位字段,将其视为IP地址,然后向客户端报告它是否落在预定的IP地址范围内。

我已经找到了几个不同的C语言代码示例,可以从包含客户端IP地址的struct sockaddr_in中获取客户端的IP地址,还有一个C#解决方案。但是,我想进一步分解这个地址,保持纯C,并想知道一些快速的问题:

我已经找到了一些不同的示例,展示了如何从struct sockaddr_in中获取客户端的IP地址,以及一个C#解决方案。然而,我想更详细地分解这个地址,只使用C语言,请问:

  1. 内部表示在系统之间是否一致,或者我是否需要在 s_addr 字段上进行大小端检查/修正?
  2. 是否有类似于 CLASS_C_NETMASKCLASS_B_NETMASK 等标准宏,比手动生成掩码(例如:0xFF0000000x00FF0000 等)更合适?
  3. 套接字库中是否存在任何现有函数,用于检查 IP 地址是否在 IP 地址范围内或与子网掩码匹配?

谢谢。


3
s_addr 始终采用“网络字节顺序”,即大端(Big-Endian)格式。 - zneak
2
你一定不会错过查看Beej's Guide to Network Programming。将其添加到您的参考/示例列表中进行检查(他的其他指南也很好)。 - David C. Rankin
1个回答

18

s_addr字段在所有平台上始终以网络(大端)字节顺序存在,因此内部表示是一致的,您不需要进行大小端检查/校正。

没有标准宏类似于CLASS_C_NETMASK、CLASS_B_NETMASK等,使用手动生成的掩码(例如:0xFF000000,0x00FF0000等)更为合适也没有意义。由于子网掩码在一个网络到另一个网络是不固定的,您需要向代码提供实际的网络IP和其子网掩码(提示用户、查询操作系统等)。然后,您可以计算子网的起始IP和结束IP来与目标IP进行比较:

uint32_t ip = ...; // value to check
uint32_t netip = ...; // network ip to compare with
uint32_t netmask = ...; // network ip subnet mask
uint32_t netstart = (netip & netmask); // first ip in subnet
uint32_t netend = (netstart | ~netmask); // last ip in subnet
if ((ip >= netstart) && (ip <= netend))
    // is in subnet range...
else
    // not in subnet range...

更简单地说,使用子网掩码来进行网络IP和目标IP的屏蔽,查看结果是否一致(即它们是否在同一子网中):

Or simpler, mask both network IP and target IP with the subnet mask and see if the resulting values are the same (ie, they are the same subnet):

uint32_t ip = ...; // value to check
uint32_t netip = ...; // network ip to compare with
uint32_t netmask = ...; // network ip subnet mask
if ((netip & netmask) == (ip & netmask))
    // is on same subnet...
else
    // not on same subnet...

sockets库中是否存在可以检查IP地址是否在IP地址范围内或匹配子网掩码的现有函数?

没有。但手动实现非常简单,只需要几行代码,如上所示。


2
非常有帮助的解决方案,谢谢!我建议从netend中减去1,以获得子网上的最后一个地址。 - Bent Cardan
2
子网上的最后一个地址是子网的广播IP。使用子网掩码屏蔽网络IP会产生广播IP,这仍然是子网的一部分。如果您不想在比较中允许广播IP,则可以从netend减去1,或者将<= netend更改为< netend,或者用子网掩码的反向屏蔽目标IP并查看结果是否与掩码相同(如果是,则目标是广播IP)。 - Remy Lebeau
当子网掩码为32时,它会失败,你有什么想法为什么会这样? - foobar
1
32是十六进制0x20,二进制为00100000。该子网掩码的高位不是连续的1位。在IPv4中,这在技术上并不违法(在IPv6中是),但它是不被鼓励和很少在实践中使用的。子网掩码的高位应始终是连续的1位。 - Remy Lebeau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接