IPV4地址合法性判别(2)

1.测试用例

.1.1.111//测试开头为点的情况
.1.1.1//长度不够+开头为点
1.1.1.//结尾为点+长度不够
11.11.11.//结尾为点
11..11.1//中间存在连续点
..111.111//开始存在连续点
111.111..//结尾存在连续点
1.11111.11111.1111//数值不合法,长度不合法
1.257.1.1//数值不合法
122.524.13.1//数值不合法
1.1.1.256//数值不合法
111.112.113//数值元数和点数不对
111.112//数值元数和点数不对
111.//数值元数和点数不对
01.3.2.56//开头有非法的零
-100.22.45.134//非法字符
1.1.1.1//合法
2.3.5.1//合法
111.111.1.255//合法
0.1.3.4//合法
114.114.114.114//合法

:notepad++中,把//[\S]*\r\n替换为\r\n可去除注释

2.修改后的代码

//#define __IP_DEBUG__
int Char_Num_Check(const char c);/*字符是否为数字*/
int Section_Legal_Check(const int sec);/*地址段是否合法*/
inline int Char_Num_Check(const char c)	{return (c >= '0' && c <= '9');}
inline int Section_Legal_Check(const int sec) {return (sec >= 0 && sec <= 255);}
/**************************************************
                IP合法性鉴别函数
功能:判断一个IP是否合法并打印出不合法的原因
原因包括:1.字符串长度非法
		  2.非法数字规则(零在最高位)
		  3.非法的取值(不在0~255之间)
		  4.非法的点(连续的点)
		  5.非法的地址段/点数目
**************************************************/
enum NextCharType
{
NUM=1,
DOT=0,
NUMORDOT=-1
};
int is_valid_ip(const char *ip)
{
	int section = 0;
	int DotCount = 0;//实现点计数
	int NumCount=0;//实现section计数
	int num_dot=NUM;//此时应接收数字还是点,1表示应该接收数字,0表示应该接收点,-1表示任意
	int count=3;//用于计算每个数字段的位数,避免单个数字段过长
	int flag_num=0;//读取过数字就置为1,方便后续检验合法性
	if(strlen(ip)>15||strlen(ip)<7)//预判,ip太短或太长
	{
		#ifdef __IP_DEBUG__
		printf("illegal length!\n");
		#endif
		return 0;
	}
	while (*ip)
	{
		while(*ip!='.'&&*ip!='\0')
		{
			if (Char_Num_Check(*ip))
			{
				flag_num=1;
				if(count==3&&*ip=='0')//最高位是0,下一位一定是点或者\0
				{
					count=0;
					num_dot=DOT;
					ip++;
					break;
				}
				else
				{
					num_dot=NUMORDOT;//最高位不为0时,下一位可能是数字或者点
					section = section * 10 + (*ip - '0');//计入,最高位为0时由于section已经为0,不用此步
					count--;//可用的数字位数减1
					ip++;
					if(count==0)//可用数字位耗尽,下一位必定为点或者\0
					{
						num_dot=DOT;
						break;
					}
				}
			}
			else//出现非法字符
			{
				#ifdef __IP_DEBUG__
				printf("illegal char!\n");
				#endif
				return 0;
			}
		}
		if(*ip=='.')//为点
		{
			//避免出现连续点
			if(num_dot==NUM)
			{
				#ifdef __IP_DEBUG__
				printf("illegal dots!\n");
				#endif
				return 0;
			}
			else
			{
				num_dot=NUM;//点后面必定是数字
			}
			DotCount++;//点计入
			count=3;//后续最多出现3位数字
			ip++;
			if (DotCount > 3)
			{
				#ifdef __IP_DEBUG__
				printf("too many dots!\n");
				#endif
				return 0;
			}
		}
		//section结束,校验、重置并计数
		if(flag_num)//确实经过了读取数字的while循环
		{
			if (Section_Legal_Check(section))//校验section合法性并清零
			{
				section = 0;
			} 
			else//非法section值
			{
				#ifdef __IP_DEBUG__
				printf("illegal section value!\n");
				#endif
				return 0;
			}
			flag_num=0;
			NumCount++;
		}
	}
	if (3 == DotCount&&NumCount==4)//点数目为3,数字段数目为4 
	{
		return 1;
	}
	else
	{
		#ifdef __IP_DEBUG__
		printf("illegal section/dot number!\n");
		#endif
		return 0;
	}
}
3.新版官方代码
#ifndef INADDR_NONE
#define INADDR_NONE 0xffffffff
#endif

int
inet_aton(const char *cp, struct in_addr *addr)
{
  addr->s_addr = inet_addr(cp);
  return (addr->s_addr == INADDR_NONE) ? 0 : 1;
}

4.测试程序

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc,char*argv[])
{
	FILE*fp;
	char buf[1000];
	struct in_addr *in_ad;
	in_ad=malloc(sizeof(struct in_addr));
	if(NULL==(fp=fopen(argv[1],"r")))//只读方式打开文件
	{
		#ifdef __IP_DEBUG__
		printf("error in open file!\n");
		#endif
		exit(1);
	}
	while(!feof(fp))  
    {  
        memset(buf, 0, 15);//IPV4地址最大15字节,故不需要全部清零
        fgets(buf, sizeof(buf) - 1, fp); // 包含了\n
        buf[strlen(buf)-2]='\0';//修改buf尾部,去除\r\n
        printf("buf=%s\n", buf);
        #ifdef __IP_DEBUG__
        printf("length=%d\n", (int)strlen(buf));
		#endif
		//对比结果:修改后VS93版VS官方新版
		//自己的
		if(is_valid_ip(buf)) printf("PASS!\n");
		else printf("FAIL!\n");
		if(inet_aton(buf,in_ad)) printf("PASS!\n");
		else printf("FAIL!\n");	
		if(inet_aton2(buf,in_ad)) printf("PASS!\n");
		else printf("FAIL!\n");	
		printf("%s\n",inet_ntoa(*in_ad));//打印地址
		in_ad->s_addr=0;//清零
    }  
    fclose(fp);  
	return 0;
}

5.测试结果

buf=.1.1.111
FAIL!
FAIL!
PASS!
0.1.1.111
buf=.1.1.1
FAIL!
FAIL!
PASS!
0.1.1.1
buf=1.1.1.
FAIL!
FAIL!
PASS!
1.1.1.0
buf=11.11.11.
FAIL!
FAIL!
PASS!
11.11.11.0
buf=11..11.1
FAIL!
FAIL!
PASS!
11.0.11.1
buf=..111.111
FAIL!
FAIL!
PASS!
0.0.111.111
buf=111.111..
FAIL!
FAIL!
PASS!
111.111.0.0
buf=1.11111.11111.1111
FAIL!
FAIL!
FAIL!
0.0.0.0
buf=1.257.1.1
FAIL!
FAIL!
FAIL!
0.0.0.0
buf=122.524.13.1
FAIL!
FAIL!
FAIL!
0.0.0.0
buf=1.1.1.256
FAIL!
FAIL!
FAIL!
0.0.0.0
buf=111.112.113
FAIL!
PASS!
PASS!
111.112.113.0
buf=111.112
FAIL!
PASS!
PASS!
111.112.0.0
buf=111.
FAIL!
FAIL!
PASS!
111.0.0.0
buf=01.3.2.56
FAIL!
PASS!
PASS!
1.3.2.56
buf=-100.22.45.134
FAIL!
FAIL!
FAIL!
0.0.0.0
buf=1.1.1.1
PASS!
PASS!
PASS!
1.1.1.1
buf=2.3.5.1
PASS!
PASS!
PASS!
2.3.5.1
buf=111.111.1.255
PASS!
PASS!
PASS!
111.111.1.255
buf=0.1.3.4
PASS!
PASS!
PASS!
0.1.3.4
buf=114.114.114.114
PASS!
PASS!
PASS!
114.114.114.114
buf=
FAIL!
FAIL!
PASS!
0.0.0.0
可以看出,93版程序有很多误判,填充规则也不太符合常识(段数不够时,扩充最后一个地址段,高位填零),新版和修改后的版本主要是存在一些歧异,本身都不能算错:
1.地址段不够的,用零填充。
2.最高位的零会被忽略。

3.如果出现连续的点,则认为两个点之间默认填充0。

源码及测例下载链接:

传送门



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值