ip有效性检测及代码优化

  说明:最近编写代码时,需要用C语言实现设置ip地址的功能,奈何本人所涉及的能力有限,通过网上查阅,找到了一个可以使用的程序代码,其中,有个检查ip地址是否有效的函数,但该函数却存在着一些不安全性,恰同时我刚好需要该函数,因此,我对该函数进行了一些优化,在此,想分享一下自己在优化该程序过程中的一些想法和思路。借此,希望能够和各位前辈进行交流。其中,原代码编写者的博客地址是:https://blog.csdn.net/lihuibo128/article/details/43668065  。

  如果该代码还存在着不足,希望各位前辈能够批评指正。

一、源程序函数

包含的头文件:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<string.h>
#include<regex.h>

 源程序:

/*
函数返回值:
    0    :成功
    -1    :失败
*/
int check_right_ip(const char *ip)
{    
    int status = 0;
    int cflags = REG_EXTENDED;
    regmatch_t pmatch[1];
    const size_t nmatch = 1;
    regex_t reg;
    char str_ip[30] = "";
    const char *pattern = "[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}";//存在局限
    
    strcpy(str_ip, ip);
    regcomp(&reg, pattern, cflags);
    status = regexec(&reg,str_ip,nmatch,pmatch,0);
    if(status==REG_NOMATCH)
    {
            printf("No match\n");
        return -1;
    }
    else if(status == 0)
    {
        return 0;    
    }
    regfree(&reg);
     return 0;
}

  说明:在源程序中,所使用的是利用正则表达式来进行数据位的有效检测,关于正则表达式函数的的用法,由于本篇主要侧重点在于代码的优化,在此,并不多详细讲解。可以参考网上其他博主的相关介绍。该程序的测试主程序如下:

int main()
{
    char *ip = "192.168.1.12";
    int res = 0;
    
    res = check_right_ip(ip);
    if (res == -1)
    {
        fprintf(stdout, "the format of ip is wrong...\r\n");
        return -1;
    }
    fprintf(stdout, "the format of ip is right\r\n");
    
    return 0;
}

 运行结果:

  通过运行结果,可以看到,该程序运行正常。

二、程序的优化之数据有效性的检测

  通过上述的简单测试,可以看到,该程序可以正常运行,但却存在着一些潜在的bug。首先,我们都知道,IP的有效格式是:"192.168.1.12",但比如有一天有人想输入的ip地址是:“192.168.1.12.12”,那么该程序的的运行结果是怎么的呢,如下是测试的主程序:

int main()
{
    char *ip = "192.168.1.12.12";
    int res = 0;
    
    res = check_right_ip(ip);
    if (res == -1)
    {
        fprintf(stdout, "the format of ip is wrong...\r\n");
        return -1;
    }
    fprintf(stdout, "the format of ip is right\r\n");
    
    return 0;
}

编译运行之后的结果如下:

  通过结果发现,该程序竟然运行正确,但这是我们想要的结果吗?结果是否定的,因此,我们需要考虑如果避免这种情况,通过对比两个ip地址我们可以发现,其中的点"."的个数是不一样的,因此,我们可以来计算该点的个数来判断一下ip地址的有效性。修改之后的check_right_ip()的函数如下:

/*
函数返回值:
    0    :成功
    -1    :失败
*/
int check_right_ip(const char *ip)
{    
    int status = 0;
    int cflags = REG_EXTENDED;
    regmatch_t pmatch[1];
    const size_t nmatch = 1;
    regex_t reg;
    char str_ip[30] = "";
    const char *pattern = "[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}";//存在局限
    
    /**************new add **********************/
    char *pNext = NULL;
    char *pTmp = NULL;
    int count = 0;
    
    strcpy(str_ip, ip);
    regcomp(&reg, pattern, cflags);
    status = regexec(&reg, str_ip, nmatch, pmatch, 0);
     if(status == REG_NOMATCH)
    {
        printf("No match\n");
        return -1;
    }
    regfree(&reg);
    
   pNext = (char *)ip;
   while (1)
   {
      pTmp = strchr(pNext, '.');
      if (pTmp == NULL)
      {
         if (count != 3)
         {
            return -1;
         }
         if (count == 3)
         {
            break;
         }
      }
      count++;
      pNext = pTmp + 1;
 }
 
  
return 0; }

  说明:在该函数中,我们增加了两个了指针,来进行数据位的有效计算“.”的个数,然后根据“.”的个数来判断其是否有效。下面是修改之后程序的运行结果

  此时,可以看出,该程序的的运行结果与我们预期的结果一致,但这就结果这个问题了吗??考虑这么一种情况,假如有人小手一抖,只是在ip地址中,多增加了一个“.”,并没有在其后面添加数字,那么此时运行结果如下呢?下面我们来测试一下。主程序的代码如下:

int main()
{
    char *ip = "192.168.1.12.";
    int res = 0;
    
    fprintf(stdout, "ip = %s\r\n", ip);
    res = check_right_ip(ip);
    if (res == -1)
    {
        fprintf(stdout, "the format of ip is wrong...\r\n");
        return -1;
    }
    fprintf(stdout, "the format of ip is right\r\n");
    
    return 0;
}

运行结果如下:

  额,该程序能够运行出正确的结果。但本人在测试时,且发现,有时候并不能正确运行出结果,当时提示的错误信息是,段错误。通过排查发现,是 check_right_ip()中的pNext = pTmp + 1;这句话导致的,原因如下,当指针pTmp指向其最后一个"."时,pNexr = pTmp + 1;会指向其末尾, 再此使用strchr()函数时,就会导致段错误。此时,有两种方法解决,一种就是在 pNext = pTmp + 1; 之后,判断pNext是否等于‘\0’,另一种则是让pNext 最初指向 str_ip,而不是指向ip,因为str_ip数组中,末尾全部为'\0',使用strchr()时,不会导致指向不该指向的地址。

修改之后的check_right_ip()的函数如下:

/*
函数返回值:
    0    :成功
    -1    :失败
*/
int check_right_ip(const char *ip)
{    
    int status = 0;
    int cflags = REG_EXTENDED;
    regmatch_t pmatch[1];
    const size_t nmatch = 1;
    regex_t reg;
    char str_ip[30] = "";
    const char *pattern = "[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}";//存在局限
    
    /**************new add **********************/
    char *pNext = NULL;
    char *pTmp = NULL;
    int count = 0;
    
    strcpy(str_ip, ip);
    regcomp(&reg, pattern, cflags);
    status = regexec(&reg, str_ip, nmatch, pmatch, 0);
     if(status == REG_NOMATCH)
    {
        printf("No match\n");
        return -1;
    }
    regfree(&reg);
    
    /**************new add **********************/
    pNext = (char *)ip;
    while (1)
    {
        pTmp = strchr(pNext, '.');
        if (pTmp == NULL)
        {
            if (count != 3)
            {
                return -1;
            }
            if (count == 3)
            {
                break;
            }
        }
        count++;
        pNext = pTmp + 1;
        
        if (*pNext == '\0')
        {
            return -1;                
        }
    }
    
     return 0;
}

  此时,我们就将其格式讨论完了,但是,假如我们输入的ip地址是:"192.168.278.12"时呢?从实际情况上出发,该字符串是不符合ip地址规范的,我们来具体的测试一下:

主程序源码:

int main()
{
    char *ip = "192.168.1.278";
    int res = 0;
    
    fprintf(stdout, "ip = %s\r\n", ip);
    res = check_right_ip(ip);
    if (res == -1)
    {
        fprintf(stdout, "the format of ip is wrong...\r\n");
        return -1;
    }
    fprintf(stdout, "the format of ip is right\r\n");
    
    return 0;
}

运行结果:

  我们发现,其结果与我们想的不同,想来原因也是,我们使用正则表达式来进行判断时,并没有对其进行数字大小的判断,因此,我们需要对其数据的有效性进行判断,修改之后的源码如下:

check_right_ip源码:

int check_right_ip(const char *ip)
{    
    int status = 0;
    int cflags = REG_EXTENDED;
    regmatch_t pmatch[1];
    const size_t nmatch = 1;
    regex_t reg;
    char str_ip[30] = "";
    const char *pattern = "[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}";//存在局限
    
    /**************new add **********************/
    char *pNext = NULL;
    char *pTmp = NULL;
    int count = 0;
    char tmpBuf[4] = {0};
        
    strcpy(str_ip, ip);
    regcomp(&reg, pattern, cflags);
    status = regexec(&reg, str_ip, nmatch, pmatch, 0);
     if(status == REG_NOMATCH)
    {
        printf("No match\n");
        return -1;
    }
    regfree(&reg);
    
    /**************new add **********************/
    pNext = (char *)ip;
    while (1)
    {
        pTmp = strchr(pNext, '.');
        if (pTmp == NULL)
        {
            if (count != 3)
            {
                return -1;
            }
            if (count == 3)
            {
                break;
            }
        }
        count++;
        pNext = pTmp + 1;
        
        if (*pNext == '\0')
        {
            return -1;                
        }
    }
    
    pNext = (char *)str_ip;
    while (count--)
    {
        pTmp = strchr(pNext, '.');
        if((pTmp - pNext) == 3)
        {
            strncpy(tmpBuf, pNext, 3);
            if (atoi(tmpBuf) > 255)
            {
                return -1;
            }
            memset(tmpBuf, 0, sizeof(tmpBuf));
        }
        
        pNext = pTmp + 1;
        
    }
    
     return 0;
}

运行结果:

  此时,运行结果与想象宏的结果一致。。

猜你喜欢

转载自www.cnblogs.com/gykai/p/9976990.html