C语言实现IP地址合法性检测和子网匹配

#include <stdio.h>
#include <stdlib.h>
#ifdef WIN32
#include <Winsock2.h>
#else
#include <fcntl.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <netdb.h>
#include <errno.h>

#include <sys/un.h> 
#include <linux/types.h> 
#include <linux/netlink.h> 
#include  <linux/if.h>
#include  <linux/sockios.h>
#include  <linux/ethtool.h>

#ifdef WIN32
#pragma comment(lib,"wsock32.lib")
#endif

/*参数UINT32都为网络字节顺序。*/

/*IP地址是否合法, 合法返回TURE,失败返回FALSE*/
int netIpIsValid(_UINT32 IP)
{
    int i;
    struct in_addr addr;
    addr.s_addr = IP;
    
    i = inet_addr(inet_ntoa(addr));

    if((i == 0)||(i == 0xffffffff))
        return FALSE;
    else
        return TRUE;
}
   
/*MASK子网掩码是否合法, 合法返回TURE,失败返回FALSE*/
int netMaskIsValid(_UINT32 mask)
{
    int i;
    unsigned long ii;
    i = netIpIsValid(mask);
    if(i==TRUE)
    {
        ii = ntohl(mask);
        if((ii|ii-1)==0xffffffff)
        {
            return TRUE;
        }
    }
    
    return FALSE;
}

/*MASK子网掩码是否合法, 合法返回TURE,失败返回FALSE*/
int netMaskAndIpIsValid(_UINT32 IP, _UINT32 mask)
{
    int i;
    int a, b=0, c;
    i = netIpIsValid(IP);
    if(i!=TRUE)
        return FALSE;
    i = netMaskIsValid(mask);
    if(i!=TRUE)
        return FALSE;

    a = IP&0x000000ff;
    b = ntohl(mask);

    /*首先与默认子网掩码比较*/
    if(a>0&&a<127)
    {
        if(mask<0x000000ff)
            return FALSE;
        if(mask>0x000000ff)
            b-=0xff000000;
    }
    if(a>=128&&a<=191)
    {
        if(mask<0x0000ffff)
            return FALSE;
        if(mask>0x0000ffff)
            b-=0xffff0000;
    }
    if(a>=192&&a<=223)
    {
        if(mask<0x00ffffff)
            return FALSE;
        if(mask>0x00ffffff)
            b-=0xffffff00;
    }

    /*每个子网段的第一个是网络地址,用来标志这个网络,最后一个是广播地址,用来代表这个网络上的所有主机.这两个IP地址被TCP/IP保留,不可分配给主机使用.*/
    c = ~ntohl(mask)&ntohl(IP);
    if(c==0||c==~ntohl(mask))
        return FALSE;

    /*RFC 1009中规定划分子网时,子网号不能全为0或1,会导致IP地址的二义性*/
    if(b>0)
    {
        c = b&(ntohl(IP));
        if(c==0||c==b)
            return FALSE;
    }

    return TRUE;
}

/*测试主网和子网是否匹配,也可测试两个主机IP是否在同一网段内*/
int netIPAndSubnetValid(_UINT32 IP, _UINT32 subIP, _UINT32 mask)
{
    int i;
    int addr1, addr2;
    i = netMaskAndIpIsValid(IP, mask);
    if(i!=TRUE)
    	return FALSE;
    i = netMaskAndIpIsValid(subIP, mask);
    if(i!=TRUE)
    	return FALSE;

    addr1 = IP&mask;
    addr2 = subIP&mask;

    if(addr1!=addr2)
    	return FALSE;

    return TRUE;
}


技术实现及功能:
1. 用C语言实现
2. 判断IP地址是否合法
3. 判断MASK是否合法
4. 判断MASK和IP地址组合是否合法

测试:

测试环境:win7 VC++;
测试结果:
 1、测试IP是否合法:
   输入IP为0xFFFFFFFF即255.255.255.255,结果为不合法;
   输入IP为0x00000000即0.0.0.0,结果为不合法;
   输入IP为0x00000000--0xFFFFFFFF即在0.0.0.0--255.255.255.255之间(全0和全1除外),结果为合法。
 2、测试子网掩码是否合法:
   输入0x00C0FFFF(1111 1111.1111 1111.1100 0000),结果合法;
   输入一个无符号int型数,二进制形式为 左边为全1右边为全0,结果合法,其余形式不合法。
 3、测试子网掩码和IP是否匹配:
   输入IP为0x410AA8C0即192.168.10.65(C类IP),输入子网掩码为0xC0FFFFFF,结果匹配,输入小于0x00FFFFFF的子网掩码时不匹配;
   输入IP为0x0141A885即133.168.65.1(B类IP),输入子网掩码为0x00C0FFFF,结果匹配,输入小于0x0000FFFF的子网掩码时不匹配;
   输入IP为0x0100413F即63.65.0.1(A类IP),输入子网掩码为0x0000C0FF,结果匹配,输入小于0x000000FF的子网掩码时不匹配。
   子网段内第一个和最后一个IP不可分配;子网号全0或全1的子网不可用,此时的结果都为不匹配。
 4、测试两个IP是否在同一子网段:
   输入两个IP为0x0C81C480 0x118FC480,输入子网掩码为0x00C0FFFF,结果为两个IP在同一网段;
   输入两个IP为0x0C81C480 0x117FC480,输入子网掩码为0x00C0FFFF,结果两个IP不在同一网段。

备注:测试数据为无符号int型,网络字节顺序。

 

 

补充知识:

一般的,32位的IP地址分为两部分,即网络号和主机号,我们分别把他们叫做IP地址的“网间网部分”和“本地部分”。子网编址技术将本地部分进一步划分为“物理网络”部分和“主机”部分,其中“物理网络”用于标识同一IP网络地址下的不同物理网络,即是“子网”。

    A类IP段  0.0.0.0 到127.255.255.255

 B类IP段  128.0.0.0 到191.255.255.255

 C类IP段  192.0.0.0 到223.255.255.255

XP默认分配的子网掩码每段只有255或0

   A类的默认子网掩码 255.0.0.0     一个子网最多可以容纳1677万多台电脑

   B类的默认子网掩码 255.255.0.0    一个子网最多可以容纳6万台电脑

   C类的默认子网掩码 255.255.255.0   一个子网最多可以容纳254台电脑
以C类地址为例。IP地址中的前3个字节表示网络号,后一个字节既表明子网号,又说明主机号,还说明两个IP地址是否属于一个网段。如果属于同一网络区间,这两个地址间的信息交换就不通过路由器。如果不属同一网络区间,也就是子网号不同,两个地址的信息交换就要通过路由器进行。

看一个例子:
       A的IP地址:11000000,10101000,00000000,00000101
        子网掩码:11111111,11111111,11111111,00000000
       B的IP地址:11000000,10101000,00000000,00010110

     看上边的内容,子网掩码在左边一共有24位为1,那这样的意思就是如果两个IP地址的前24位都相同的话,那这两个IP地址就是在同一个网段内,看到我红色标记的A和B的地址都相同,那这就说明A和B在同一个网段内。

再看一个例子,如果还是A地址的数据发到C地址,C的IP地址为192.168.56.21
     A的IP地址:11000000,10101000,00000000,00000101
      子网掩码:11111111,11111111,11111111,00000000
     C的IP地址:11000000,10101000,00111000,00010101

      看上边的A和C,按照子网掩码的要求,如果C的前24位和A的前24位都相同的话,那么A和C才是同一网段的,看上边C的地址,我用蓝色来标注不同的位数,这样A 和C就不在同一个网段内,路由器就不能直接把A要发给C的数据直接经过一个路由器给发送过去,这样路由器就要先将A的数据转发到另外一个路由器(一个不行就继续往下发),然后再发到C上。

● 字节序转换函数
htons 把 unsigned short 类型从主机序转换到网络序
htonl 把 unsigned long 类型从主机序转换到网络序
ntohs 把 unsigned short 类型从网络序转换到主机序
ntohl 把 unsigned long 类型从网络序转换到主机序
这几个函数很好记,比如htons中hton代表host to network, s代表unsigned short
char FAR * inet_ntoa( struct in_addr in);
将一个IP转换成一个互联网标准点分格式的字符串。
in_addr_t inet_addr(const char *cp);
将一个点分十进制的IP转换成一个长整数型数(u_long类型)。返回值已是网络字节顺序,可以直接作为internet 地址

 

一个函数返回值为TRUE或FALSE 只有这两种返回值时 在判断返回值时不用 if(i==TRUE)或if(i==FALSE),而用if(i) if(!i)  编程规范。

 

inet_ntoa()返回的字符串是临时装在一个静态分配的缓冲区里面,下一次调用此函数的时候缓冲区会被重写

 

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值