记IP嵌入式端IP地址合法性校验

网络地址信息合法性校验

  对于网络信息,在由远端设置本地设备时,在防御机制上,需要对网络信息进行合法性校验,常用的我们是对msk(掩码)、IPV4、gw(网关)进行校验。
  近期在研究p-net协议栈,发现一个很漂亮的校验写法,在此做一下记录。
源码:p-net协议栈中pf_cmina.c文件。

掩码校验

  校验掩码,首先掩码定义是什么?

子网掩码(subnet mask)又叫网络掩码、地址掩码、子网络遮罩,它用来指明一个IP地址的哪些位标识的是主机所在的子网,以及哪些位标识的是主机的位掩码。子网掩码不能单独存在,它必须结合IP地址一起使用。子网掩码是一个32位地址,用于屏蔽IP地址的一部分以区别网络标识和主机标识,并说明该IP地址是在局域网上,还是在广域网上。《百度百科》

类别子网掩码的二进制数值子网掩码的十进制数值
A11111111 00000000 00000000 00000000255.0.0.0
B11111111 11111111 00000000 00000000255.255.0.0
C11111111 11111111 11111111 00000000255.255.255.0

子网掩码一定是配合IP地址来使用的。对于常用网络A、B、C类IP地址其默认子网掩码的二进制与十进制对应关系如表1所示。子网掩码工作过程是:将32位的子网掩码与IP地址进行二进制形式的按位逻辑“与”运算得到的便是网络地址,将子网掩码二进制按位取反,然后与IP地址二进制进行逻辑“与”(AND)运算,得到的就是主机地址。如:192.168.10.11 AND 255.255.255.0,结果为192.168.10.0,其表达的含义为:该IP地址属于 192.168.10.0这个网络,其主机号为11,即这个网络中编号为11的主机。


  因此子网掩码在二进制中的标识以连续的1和连续的0构成。并且连续的1在高字节,0在低字节。

 &emsp有效子网掩码的二进制形式必须满足:
netmask = 2 n − 2 m ( n > m ) \text{netmask} = 2^n - 2^m \quad (n > m) netmask=2n2m(n>m)
其中 n n n 为总位数, m m m 为低位连续0的位数。例如 11110000 对应 n = 8 n=8 n=8, m = 4 m=4 m=4
  在p-net中应用了一个很基础的数学运算,来判断是否是合法的掩码。掩码参数为netmask;

   if (!(netmask & (~netmask >> 1)))
   {
      return true;
   }
   else
   {
      return false;
   }

二进制运算步骤拆解

1. 按位取反 (~netmask)
假设输入 netmask 的二进制形式为 11110000(十进制240),取反后得到 00001111。该操作将原掩码的所有位翻转。

2. 右移一位 (>> 1)
对取反后的值右移一位:00001111 >> 1 = 00000111。右移会在左侧补0,相当于除以2(向下取整)。

3. 按位与操作 (&)
将原始 netmask 与上一步结果进行按位与:
11110000 & 00000111 = 00000000
只有对应位均为1时结果位才为1,否则为0。

4. 逻辑非 (!)
若按位与结果为0(即所有位均为0),逻辑非操作将其转为 true,表示该掩码有效;否则为 false

关键逻辑总结

该表达式通过位运算快速检测是否存在非连续的1和0交替情况。仅当掩码的高位1和低位0严格连续时,netmask & (~netmask >> 1) 的结果为0,使条件成立。

IP校验

IP地址根据其网络和主机部分的划分,主要分为五类:A、B、C、D、E。

A类地址
  • 范围:1.0.0.0 到 126.255.255.255
  • 特点
    • 保留地址:10.0.0.0/8(私有地址)。
B类地址
  • 范围:128.0.0.0 到 191.255.255.255
  • 特点
    • 保留地址:172.16.0.0/12(私有地址)。
C类地址
  • 范围:192.0.0.0 到 223.255.255.255
  • 特点
    • 保留地址:192.168.0.0/16(私有地址)。
D类地址
  • 范围:224.0.0.0 到 239.255.255.255
  • 特点
    • 用于组播(Multicast),无网络和主机划分。
    • 最高位固定为1110。
E类地址
  • 范围:240.0.0.0 到 255.255.255.255
  • 特点
    • 保留用于实验或未来使用,最高位固定为1111。

特殊地址说明

  • 127.0.0.0/8:环回地址(如127.0.0.1)。
  • 0.0.0.0:表示默认路由或无效地址。
  • 255.255.255.255:受限广播地址。

私有地址范围

  • A类:10.0.0.0/8
  • B类:172.16.0.0/12
  • C类:192.168.0.0/16

这些分类和范围是IPv4地址设计的基础,实际应用中可能结合子网划分(CIDR)进一步优化地址分配。
由与IPV4的分类,故与外围设备通信,对于IP地址的范围便有了限制。pnet协议栈对此的防御机制很全面,我们看一下。先贴代码。

#define PNAL_MAKEU32(a, b, c, d)                                               \
   (((uint32_t) ((a)&0xff) << 24) | ((uint32_t) ((b)&0xff) << 16) |            \
    ((uint32_t) ((c)&0xff) << 8) | (uint32_t) ((d)&0xff))
/* 
传参: netmask,ip
*/
    {
    uint32_t host_part = ip & ~netmask;

   if ((netmask == 0) && (ip == 0))
   {
      return true;
   }
   if (!pf_cmina_is_netmask_valid (netmask))
   {
      return false;
   }
   if ((host_part == 0) || (host_part == ~netmask))
   {
      return false;
   }
   if (ip <= PNAL_MAKEU32 (0, 255, 255, 255))
   {
      return false;
   }
   else if (
      (ip >= PNAL_MAKEU32 (127, 0, 0, 0)) &&
      (ip <= PNAL_MAKEU32 (127, 255, 255, 255)))
   {
      return false;
   }
   else if (
      (ip >= PNAL_MAKEU32 (224, 0, 0, 0)) &&
      (ip <= PNAL_MAKEU32 (239, 255, 255, 255)))
   {
      return false;
   }
   else if (
      (ip >= PNAL_MAKEU32 (240, 0, 0, 0)) &&
      (ip <= PNAL_MAKEU32 (255, 255, 255, 255)))
   {
      return false;
   }
   return true;
    }

逐部分解析

计算主机部分

uint32_t host_part = ip & ~netmask;

通过IP地址与子网掩码的反码进行按位与操作,提取主机部分。主机部分用于后续判断是否为网络地址或广播地址。

全零IP和子网掩码检查

if ((netmask == 0) && (ip == 0))
{
   return true;
}

当子网掩码和IP地址均为0时,视为特殊情况直接返回有效。这种情况可能表示默认路由或无地址状态。

子网掩码有效性检查

if (!pf_cmina_is_netmask_valid (netmask))
{
   return false;
}

调用外部函数pf_cmina_is_netmask_valid验证子网掩码是否合法。子网掩码必须由连续的1和0组成,例如255.255.255.0是合法的。

网络地址和广播地址检查

if ((host_part == 0) || (host_part == ~netmask))
{
   return false;
}

主机部分全0表示网络地址,主机部分全1表示广播地址,这两种情况都视为无效。

特殊IP范围检查

if (ip <= PNAL_MAKEU32 (0, 255, 255, 255))
{
   return false;
}

排除0.0.0.0到0.255.255.255范围的地址,这些通常用于特殊用途。

else if (
   (ip >= PNAL_MAKEU32 (127, 0, 0, 0)) &&
   (ip <= PNAL_MAKEU32 (127, 255, 255, 255)))
{
   return false;
}

排除127.0.0.0到127.255.255.255范围的地址,这是本地回环地址范围。

else if (
   (ip >= PNAL_MAKEU32 (224, 0, 0, 0)) &&
   (ip <= PNAL_MAKEU32 (239, 255, 255, 255)))
{
   return false;
}

排除224.0.0.0到239.255.255.255范围的地址,这是D类多播地址范围。

else if (
   (ip >= PNAL_MAKEU32 (240, 0, 0, 0)) &&
   (ip <= PNAL_MAKEU32 (255, 255, 255, 255)))
{
   return false;
}

排除240.0.0.0到255.255.255.255范围的地址,这是E类保留地址范围。

默认返回

return true;

如果以上所有检查都通过,则认为IP地址有效。### 代码功能概述
这段代码用于验证一个IPv4地址是否有效,主要检查以下几个方面:

  • 是否为网络地址或广播地址
  • 子网掩码是否有效
  • 是否属于保留或特殊用途的IP地址范围

逐部分解析

计算主机部分

uint32_t host_part = ip & ~netmask;

通过IP地址与子网掩码的反码进行按位与操作,提取主机部分。主机部分用于后续判断是否为网络地址或广播地址。

全零IP和子网掩码检查

if ((netmask == 0) && (ip == 0))
{
   return true;
}

当子网掩码和IP地址均为0时,视为特殊情况直接返回有效。这种情况可能表示默认路由或无地址状态。

子网掩码有效性检查

if (!pf_cmina_is_netmask_valid (netmask))
{
   return false;
}

调用外部函数pf_cmina_is_netmask_valid验证子网掩码是否合法。子网掩码必须由连续的1和0组成,例如255.255.255.0是合法的。

网络地址和广播地址检查

if ((host_part == 0) || (host_part == ~netmask))
{
   return false;
}

主机部分全0表示网络地址,主机部分全1表示广播地址,这两种情况都视为无效。

特殊IP范围检查

if (ip <= PNAL_MAKEU32 (0, 255, 255, 255))
{
   return false;
}

排除0.0.0.0到0.255.255.255范围的地址,这些通常用于特殊用途。

else if (
   (ip >= PNAL_MAKEU32 (127, 0, 0, 0)) &&
   (ip <= PNAL_MAKEU32 (127, 255, 255, 255)))
{
   return false;
}

排除127.0.0.0到127.255.255.255范围的地址,这是本地回环地址范围。

else if (
   (ip >= PNAL_MAKEU32 (224, 0, 0, 0)) &&
   (ip <= PNAL_MAKEU32 (239, 255, 255, 255)))
{
   return false;
}

排除224.0.0.0到239.255.255.255范围的地址,这是D类多播地址范围。

else if (
   (ip >= PNAL_MAKEU32 (240, 0, 0, 0)) &&
   (ip <= PNAL_MAKEU32 (255, 255, 255, 255)))
{
   return false;
}

排除240.0.0.0到255.255.255.255范围的地址,这是E类保留地址范围。

默认返回

return true;

如果以上所有检查都通过,则认为IP地址有效。

网关检查

网关就没那么多讲究了,检查一下不为0,与IP在同一子网即可。

   if ((gateway != 0) && ((ip & netmask) != (gateway & netmask)))
   {
      return false;
   }
   return true;

逻辑拆解

(gateway != 0)
验证网关地址是否为非零值。若网关为0(未设置),直接跳过后续检查。
(ip & netmask) != (gateway & netmask)
通过按位与运算比较:

  • ip & netmask 获取IP地址的网络标识
  • gateway & netmask 获取网关的网络标识
    当两者不一致时,说明IP与网关不在同一子网。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值