确定字符串是否是C中的有效IPv4地址

问题描述 投票:24回答:14

确定字符串是否包含IPv4地址的好方法是什么?我应该使用isdigit()吗?

c string
14个回答
51
投票

我问a similar question for C++。您应该能够使用我当时提出的稍微修改过的(对于C)版本。

bool isValidIpAddress(char *ipAddress)
{
    struct sockaddr_in sa;
    int result = inet_pton(AF_INET, ipAddress, &(sa.sin_addr));
    return result != 0;
}

你需要使用#include <arpa/inet.h>来使用inet_pton()函数。

根据对问题的评论进行更新:如果您想知道C风格的字符串是否包含IP地址,那么您应该结合到目前为止给出的两个答案。使用正则表达式查找与IP地址大致匹配的模式,然后使用上面的函数检查匹配项以查看它是否真实。


0
投票

这是我一直在努力的功能的开始,虽然不完整,它可能会引发想法或评论。功能背后的思想是;

  1. 检查传递的char指针或字符串是否是一个没有端口的IPv4地址,使用其最小/最大大小,字符串中有多少个点,以及冒号:字符是否存在。
  2. 如果字符串不是带有或没有端口的IPv4,那么检查该字符串是否为IPv6,如果不是IPv6,则无法识别IP格式,因为它尚未实现。

我认为这取决于你想要深入研究这个问题的深度,你想要了解可能会出现什么样的问题。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>

int isIP(char *ip)
{
    char *data_ptr = ip;    // Create a pointer to passed data
    int orig_str_size = 0;  // Create an int to hold passed data size
    int str_index = 0;      // Create an int to iterate individual ip characters
    int dot_count = 0;      // Create an int to check for the number of dots

    // Count the number of characters in data_ptr
    while (*data_ptr++ != '\0'){ orig_str_size++; }

    if(orig_str_size <= 0) // If nothing
    {
        printf("Get a grip, ip is empty\n\n");
        exit(0);
    }
    else // If within IPv4 size range
    if(orig_str_size >= 7 && orig_str_size <= INET_ADDRSTRLEN)
    {
        char *data1_ptr = ip; // Create a pointer to passed data
        printf("Within IPv4 range, %i characters in length\n\n", orig_str_size);

        // Count the number of dots in the string, 3 for IPv4
        for(str_index; str_index < orig_str_size; str_index++)
        {
            if(data1_ptr[str_index] == '.'){ dot_count++; }
        }

        // If theres 3 dots, while ignoring dots, check each char is a digit 
        if(dot_count == 3)
        {

            printf("There's three dots in the string\n\n");
            data1_ptr = ip;
            str_index = 0;

            // Iterate the string char by char
            for(str_index; str_index < orig_str_size; str_index++)
            {
                // Ignoring dots
                if(data1_ptr[str_index] != '.')
                { 
                    // If isdigit() is happy its a digit and isalpha() happy not alphabetic
                    if(isdigit(data1_ptr[str_index]) && !isalpha(data1_ptr[str_index]))
                    {
                        printf("Digit found and is not alphabetic\n\n");
                        continue;
                    }
                    else
                    if(!isdigit(data1_ptr[str_index]) && isalpha(data1_ptr[str_index]))
                    {
                        printf("Not a recognised IPv4 address, character detected in string\n\n");
                        exit(0);
                    }
                }
            }

            return 0;
        }
    }
    else // If IPv6
    if(orig_str_size > 0 && orig_str_size > INET_ADDRSTRLEN && orig_str_size <= INET6_ADDRSTRLEN)
    {
        printf("Within IPv6 range %i\n\n", orig_str_size);
        return 0;
    }
    else
    {
        printf("Unknown target format, the format you provided as a target is not implemented\n\n");
        exit(0);
    }

}

TCP / IP网络互联

RFC791 - 互联网协议 - https://tools.ietf.org/html/rfc791

CISCO网络互联手册http://docwiki.cisco.com/wiki/Internetworking_Technology_Handbook

开放系统互连参考模型http://docwiki.cisco.com/wiki/Internetworking_Basics#Open_Systems_Interconnection_Reference_Model

CISCO故障排除TCP / IP网络https://www.cisco.com/en/US/docs/internetworking/troubleshooting/guide/tr1907.pdf

What is the largest TCP/IP network port number allowable for IPv4?


0
投票
//  you can even use the v value array to return the unsigned int 
//  version of the IP if desired in an unsigned int reference.   

bool isvalidip(const char * s) 
{
  char t[8];
  int p = 0;
  int v[8];
  int numnum = 0;
  for (int i = 0; i < (int) strlen(s); i++) {
    char c = s[i];
    int cgood = 0;
    if (c >= '0' && c <= '9' && p < 4) {
      t[p++] = c;
      t[p] = 0;
      cgood++;
      continue;
    }
    if (p == 4) return false;
    if (c == '.') {
      if (!p) return false;
      v[numnum++] = atoi(t);
      p = 0;
      cgood++;
      continue;
    }
    if (!cgood) return false; // not a valid character
    if (numnum > 4) return false; // we have a lot of dots....
  }
  v[numnum++] = atoi(t); // we did not have a dot, we had a NULL.....
  if (numnum != 4) return false; // we must have had 4 valid numbers....
  for (int i = 0; i < 4; i++)
  {
    if (v[i] < 0 || v[i] > 255) return false; // octet values out-of-range
  }
  return true; //we good..
}

0
投票

我修改了其中一个答案,使其更加完整并附上所有代码(包括测试)

#include <stdio.h>
#include <assert.h>
#include <string.h>

int validateIP4Dotted(char *str, unsigned int pIPAddress[])
{
    int segs = 0; /* Segment count. */
    int chcnt = 0; /* Character count within segment. */
    int accum = 0; /* Accumulator for segment. */

    /* Catch NULL pointer. */

    if (str == NULL)
        return 0;

    /* Process every character in string. */

    while (*str != '\0')
    {
        /* Segment changeover. */

        if (*str == '.')
        {
            pIPAddress[segs] = accum;
            /* Must have some digits in segment. */

            if (chcnt == 0 || chcnt > 3)
                return 0;

            /* Limit number of segments. */

            if (++segs == 4)
                return 0;

            /* Reset segment values and restart loop. */

            chcnt = accum = 0;
            str++;
            continue;
        }
        /* Check numeric. */

        if ((*str < '0') || (*str > '9'))
            return 0;

        /* Accumulate and check segment. */

        if ((accum = accum * 10 + *str - '0') > 255)
            return 0;

        /* Advance other segment specific stuff and continue loop. */

        chcnt++;
        str++;
    }

    /* Check enough segments and enough characters in last segment. */
    pIPAddress[segs] = accum;

    if (segs != 3)
        return 0;

    if (chcnt == 0 || chcnt > 3)
        return 0;

    if (pIPAddress[0] >=224)
        return 0;
    /* Address okay. */

    return 1;
}


int main()
{
    unsigned int IpAddress[4];
    char str_ip[128];

    strcpy(str_ip, "192.168.1.10");
    assert(validateIP4Dotted(str_ip, IpAddress));
    assert(
            IpAddress[0] == 192 && IpAddress[1] == 168 && IpAddress[2] == 1
                    && IpAddress[3] == 10);

    strcpy(str_ip, "0.0.0.0");
    assert(validateIP4Dotted(str_ip, IpAddress));
    assert(
            IpAddress[0] == 0 && IpAddress[1] == 0 && IpAddress[2] == 0
                    && IpAddress[3] == 0);

    strcpy(str_ip, "/192.168.1.10");
    assert(!validateIP4Dotted(str_ip, IpAddress));

    strcpy(str_ip, "192..168.1.10");
    assert(!validateIP4Dotted(str_ip, IpAddress));

    strcpy(str_ip, ".192.168.1.10");
    assert(!validateIP4Dotted(str_ip, IpAddress));

    strcpy(str_ip, "192.168.1.10.");
    assert(!validateIP4Dotted(str_ip, IpAddress));

    strcpy(str_ip, "192.168.1.10.10");
    assert(!validateIP4Dotted(str_ip, IpAddress));

    strcpy(str_ip, "192.168.1.");
    assert(!validateIP4Dotted(str_ip, IpAddress));

    strcpy(str_ip, "192.168.1");
    assert(!validateIP4Dotted(str_ip, IpAddress));

    strcpy(str_ip, "255.168.1.10");
    assert(!validateIP4Dotted(str_ip, IpAddress));

    strcpy(str_ip, "10.260.1.10");
    assert(!validateIP4Dotted(str_ip, IpAddress));

    strcpy(str_ip, "10.200.0001.10");
    assert(!validateIP4Dotted(str_ip, IpAddress));

    return 0;
}

-1
投票

我认为下面的C代码片段应该可行

bool validate_ip4(const char* buffer)
{
    if (NULL == buffer) return false;

    register const      char*   pos     = buffer;
    register unsigned   char    ch      = *pos;
    register unsigned   short   count   = 0;

    while (ch != NULL)
    {
        if (!((ch >= '0' && ch <= '9') || ch == '.')) return false;

        if (ch == '.')
            if (++count > 3) return false;

        ch = *++pos;
    }

    if (count == 3 && *--pos != '.') return true;

    return false;
}

-1
投票

inet_addr()比用于数字和点表示法IPv4 IP地址检查的inet_aton()要好得多。


7
投票

这是我不久前写的一个嵌入式系统的例程,它在网络上生成了各种可疑模式。因此,它绝对不使用像网络库甚至标准C库这样的花哨的东西,而是更喜欢避免所有现代的东西,如字符串标记和(颤抖)正则表达式库:-)为此,它适合于你可以找到自己的任何环境,而且速度非常快。

虽然,如果你所处的环境有像checkIp4Addess()这样的东西,我建议你改用它。这表明你在做嵌入式工作时有时需要忍受的东西(尽管这是一个真正的解决方案)。

int isValidIp4 (char *str) {
    int segs = 0;   /* Segment count. */
    int chcnt = 0;  /* Character count within segment. */
    int accum = 0;  /* Accumulator for segment. */

    /* Catch NULL pointer. */

    if (str == NULL)
        return 0;

    /* Process every character in string. */

    while (*str != '\0') {
        /* Segment changeover. */

        if (*str == '.') {
            /* Must have some digits in segment. */

            if (chcnt == 0)
                return 0;

            /* Limit number of segments. */

            if (++segs == 4)
                return 0;

            /* Reset segment values and restart loop. */

            chcnt = accum = 0;
            str++;
            continue;
        }
        /* Check numeric. */

        if ((*str < '0') || (*str > '9'))
            return 0;

        /* Accumulate and check segment. */

        if ((accum = accum * 10 + *str - '0') > 255)
            return 0;

        /* Advance other segment specific stuff and continue loop. */

        chcnt++;
        str++;
    }

    /* Check enough segments and enough characters in last segment. */

    if (segs != 3)
        return 0;

    if (chcnt == 0)
        return 0;

    /* Address okay. */

    return 1;
}

1
投票

我会使用这个正则表达式(由Regular Expression Examples提供):

`\b(?:\d{1,3}\.){3}\d{1,3}\b`

1
投票

我会给出“不要两个问题”的解决方案:

#include <string.h>



int isIp_v4( char* ip){
        int num;
        int flag = 1;
        int counter=0;
        char* p = strtok(ip,".");

        while (p && flag ){
                num = atoi(p);

                if (num>=0 && num<=255 && (counter++<4)){
                        flag=1;
                        p=strtok(NULL,".");

                }
                else{
                        flag=0;
                        break;
                }
        }

        return flag && (counter==3);

}

编辑:strtok可能不是线程安全(信任Adam Rosenfield)


1
投票

这是我尝试使用非常低级别的C编程(实际上在我的一个PIC单片机程序中使用)。它不使用string.h库。它不使用指针,因为我使用的这个编译器与它们不兼容,无论如何你可以使用它们。考虑到这一点,并且通常会定义一个变量来处理传入的数据缓冲区,如下所示:

#define isdigit(x)  isamong(x,"0123456789")
char    IPACK_Buff[IPACK_SIZE]; 

// Check if string is a valid IP
int IPACK_is_valid_ip(int len)
{
    int i = 0;
    int j = 0;
    int NumDots = 0;
    char number[4] = "000\0";

    // Check first  char is numeric
    if (!isdigit(IPACK_Buff[0])) 
        return 0;

    for (i = 0 ; i< len; i++)
    {
        if (isdigit(IPACK_Buff[i]))
        {
            number[j] = IPACK_Buff[i];
            j++;
            if (j>3)    
                return 0;
        }
        else if (IPACK_Buff[i] == '.')
        {
            if (atof(number)> 255) return 0;
            memset(number, '\0', 4);

            j = 0;
            NumDots++;
            if(NumDots>3)
                return 0;
        }
    }

    if (NumDots == 3)
    {
        return 1;
    }
    else 
        return 0;
}//

我希望这个功能可以帮助你们。再次,在批评之前考虑这个功能的低级别。


1
投票
int validateIP4Dotted(const char *s)
{
    int len = strlen(s);

    if (len < 7 || len > 15)
        return 0;

    char tail[16];
    tail[0] = 0;

    unsigned int d[4];
    int c = sscanf(s, "%3u.%3u.%3u.%3u%s", &d[0], &d[1], &d[2], &d[3], tail);

    if (c != 4 || tail[0])
        return 0;

    for (int i = 0; i < 4; i++)
        if (d[i] > 255)
            return 0;

    return 1;
}

0
投票

在url / uri rfc 3986中,Augmented Backus-Naur Form(ABNF)ipv4地址定义为:

  IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet

  dec-octet   = DIGIT                 ; 0-9
              / %x31-39 DIGIT         ; 10-99
              / "1" 2DIGIT            ; 100-199
              / "2" %x30-34 DIGIT     ; 200-249
              / "25" %x30-35          ; 250-255

我用以下形式用regex实现了检查:

// Although the RFC says ipv6 octects like 001 are not valid, it would be risky
// not to accept those
#define decoct "([01]?[0-9]?[0-9]|2[0-4][0-0]|25[0-5])"
#define ipv4 "(" decoct "\\." decoct "\\." decoct "\\." decoct ")"

0
投票

我需要弄清楚传入的字符串是否“包含”一个有效的IP地址,并返回一个指向传入字符串的有效IP地址部分的指针,如果是这样的话。如果不是,则返回空指针。

这里的代码似乎有效,虽然尚未经过良好测试,但我只是编写并快速尝试。我没有添加一个检查来限制数字到一个字节的值,但请检查以确保它们限制为三位数。

int IsDigit(char ch)
{
   int is_digit = 0;
   if ( ch >= '0' && ch <= '9' )
   {
      is_digit = 1;
   }
   return is_digit;
}

#define FIND_IP_START         0
#define FIND_IP_DIGIT         1
#define FIND_IP_DIG_OR_DEC    2
#define FIND_IP_DECIMAL       3
#define FIND_IP_DIG_OR_END    4
#define FIND_IP_END           5
#define FIND_IP_DONE          6

char * StringContainsValidIpAddress(char * input_buf_pointer)
{
   char * pos       = input_buf_pointer;
   int    octets    = 0; 
   int    digits    = 0;
   int    state     = FIND_IP_START;
   char * ip_string = 0;

   char   ch        = *pos; 

   while ( (ch != NULL) && (state != FIND_IP_DONE) )
   {
      switch ( state )
      {
      case FIND_IP_START:
         if ( IsDigit(ch) )
         {
            ip_string = pos;  //potential start of ip string
            digits = 1;   // first digit
            octets = 1;   // of first octet
            state = FIND_IP_DIG_OR_DEC;
         }
         break;
      case FIND_IP_DIGIT:
         if ( IsDigit(ch) )
         {
            digits = 1;    // first digit
            octets++;      // of next octet
            if ( octets == 4 )
            {
               state = FIND_IP_DIG_OR_END;
            }
            else
            {
                   state = FIND_IP_DIG_OR_DEC;
            }
         }
         else
         {
            // Start over
            state = FIND_IP_START;
         }
         break;
      case FIND_IP_DIG_OR_DEC:
         // Here we are looking for another digit 
         // of the same octet or the decimal between 
         // octets.
         if (ch == '.')
         {
               state = FIND_IP_DIGIT;
         }
         else if ( IsDigit(ch) )
         {
            digits++;      // next digit
            if ( digits == 3 )
            {
               state = FIND_IP_DECIMAL;
            }
         }
         else
         {
            // Start over
            state = FIND_IP_START;
         }
         break;
      case FIND_IP_DECIMAL:
         if (ch == '.')
         {
               state = FIND_IP_DIGIT;
         }
         break;
      case FIND_IP_DIG_OR_END:
         // Here we are looking for another digit 
         // of the same octet or the end (which could
         // be a space or CR or LF or really any 
         // non-digit).
         if ( IsDigit(ch) )
         {
            digits++;      // next digit
            if ( digits == 3 )
            {
               state = FIND_IP_END;
            }
         }
         else
         {  
            *pos = 0;  // Null terminate the IP address string
            state = FIND_IP_DONE;
         }
         break;
      case FIND_IP_END:
         if ( !IsDigit(ch) )
         {
            *pos = 0;  // Null terminate the IP address string
            state = FIND_IP_DONE;
         }
         break;
      case FIND_IP_DONE:
         break;
      default:
         break;
      }

      // Fetch the next character
      ch = *++pos; 
   } 

   if (state == FIND_IP_DONE) 
   {
      return ip_string; 
   }
   else
   {
      return 0;
   }
}

0
投票

像这样从头开始做。此代码包含用于检查字符串是否包含IPv4 IP地址的工具。

#define MAX_HEX_NUMBER_COUNT 8 

int ishexdigit(char ch) 
{
   if((ch>='0'&&ch<='9')||(ch>='a'&&ch<='f')||(ch>='A'&&ch<='F'))
      return(1);
   return(0);
}

int IsIp6str(char *str)
{ 
   int hdcount=0;
   int hncount=0;
   int err=0;
   int packed=0;

   if(*str==':')
   {
      str++;    
      if(*str!=':')
         return(0);
      else
      {
         packed=1;
         hncount=1;
         str++;

         if(*str==0)
            return(1);
      }
   }

   if(ishexdigit(*str)==0)
   {
      return(0);        
   }

   hdcount=1;
   hncount=1;
   str++;

   while(err==0&&*str!=0)   
   {                      
      if(*str==':')
      {
         str++;
         if(*str==':')
         {
           if(packed==1)
              err=1;
           else
           {
              str++;

          if(ishexdigit(*str)||*str==0&&hncount<MAX_HEX_NUMBER_COUNT)
          {
             packed=1;
             hncount++;

             if(ishexdigit(*str))
             {
                if(hncount==MAX_HEX_NUMBER_COUNT)
                {
                   err=1;
                } else
                {
                   hdcount=1;
                   hncount++;
                   str++;   
                }
             }
          } else
          {
             err=1;
          }
       }
    } else
    {
           if(!ishexdigit(*str))
           {
              err=1;
           } else
           {
              if(hncount==MAX_HEX_NUMBER_COUNT)
              {
                 err=1;
              } else
              {
                  hdcount=1;
                  hncount++;
                  str++;   
              }
           }
        }
     } else
     {  
        if(ishexdigit(*str))
        {
           if(hdcount==4)
              err=1;
           else
           {
              hdcount++;          
              str++;
           }
         } else
            err=1;
     } 
   }

   if(hncount<MAX_HEX_NUMBER_COUNT&&packed==0)
      err=1;

    return(err==0);
}

int IsIp4str(char *str) 
{
   int nnumber=0;
   int value=0;
   int err=0;

   if(*str>='0'&&*str<='9')
   {
      value=*str-'0';
      str++;
   } else
      return(0);

   nnumber=1;

   while(err==0&&*str!=0)
   {
      if(*str>='0'&&*str<='9')
      {
         if(255/value>=10)
         {
            value*=10;

            if(255-value>=(*str-'0'))
            {
               value+=(*str-'0');
               str++;
            } else
                err=1;
         } else
           err=1;
      }  else
      {
         if(*str=='.')
         {      
            str++;
            if(*str>='0'&&*str<='9')
            {
               if(nnumber==4)
                  err=1;
               else
               {
                  if(*str=='0')
                  {
                     *str++;
                     if(*str!='.'&&*str!=0)
                        err=1;
                     else
                     {
                        nnumber++;
                        value=0;
                     }
                  } else
                  {
                     nnumber++;
                     value=*str-'0';
                     str++;
                  }
               }
            } else
            {
               err=1;
            }
         } else
           if(*str!=0)
             err=1;
      }
   }

   if(nnumber!=4)
      err=1;

   return(err==0);
}

函数IsIp4str(char * str)测试字符串是否包含IP地址版本四地址格式。如果字符串包含IP地址版本六地址格式,则IsIp6str(char * str)函数测试。

函数IsIp4str(char * str)和IsIp6str(char * str)如果string str包含IP地址则返回true,如果string str不包含IP地址,则返回false。

如果你需要检查字符串是否包含IP地址IPv6格式,它可以完成int IsIp6str(char * str)函数。它的工作方式与此相同

© www.soinside.com 2019 - 2024. All rights reserved.