Determine if a string is a valid IPv4 address in C

后端 未结 15 1974
感情败类
感情败类 2020-12-24 08:22

What would be a good way to determine if a string contains an IPv4 address? Should I use isdigit()?

相关标签:
15条回答
  • 2020-12-24 08:32

    I modify one of the answer to make it more complete and attach all the code (include test)

    #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;
    }
    
    0 讨论(0)
  • 2020-12-24 08:36

    Heres the start of a function I've been working on, although not complete, it may spark ideas or comments. The thought behind the function is;

    1. Check the passed char pointer or string is an IPv4 address without port using its min/max size, how many dots in the string, and if the colon : character exists or not.
    2. If the string is not IPv4 with or without a port then check if the string is IPv6, if not IPv6 then IP format not recognized because it isn't implemented yet.

    I think it depends on how deep you want to go into the issue, how deep you want to go to understand what problems could occur.

    #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 Internetworking

    RFC791 - Internet Protocol - https://tools.ietf.org/html/rfc791

    The CISCO Internetworking handbook http://docwiki.cisco.com/wiki/Internetworking_Technology_Handbook

    The Open Systems Interconnection Reference Model http://docwiki.cisco.com/wiki/Internetworking_Basics#Open_Systems_Interconnection_Reference_Model

    CISCO Troubleshooting TCP/IP Networks 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 讨论(0)
  • 2020-12-24 08:39

    I'll give the "don't want two problems" solution:

    #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);
    
    }
    

    EDIT: strtok may not be thread safe (credits to Adam Rosenfield)

    0 讨论(0)
  • 2020-12-24 08:44

    I needed to figure out if incoming string "contains" a valid IP address, and to return a pointer to the portion of the incoming string that is the valid IP address, if so. If not, returns a null pointer.

    Here is code that seems to work, although not well tested yet, I just wrote it and gave it a quick try. I didn't add a check yet for limiting the numbers to one-byte values, but do check to ensure that they are limited to three digit numbers.

    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 讨论(0)
  • 2020-12-24 08:46

    In the url/uri rfc 3986, the Augmented Backus-Naur Form (ABNF) ipv4 address is defined as:

      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
    

    I implemented the check with regexp in the following form:

    // 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 讨论(0)
  • 2020-12-24 08:46
    //  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 讨论(0)
提交回复
热议问题