Подтвердить что ты не робот

Определите, является ли строка действительным адресом IPv4 в C

Что было бы хорошим способом определить, содержит ли строка адрес IPv4? Должен ли я использовать isdigit()?

4b9b3361

Ответ 1

Я задал похожий вопрос для 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-адресу, а затем используйте функцию выше, чтобы проверить соответствие, чтобы увидеть, если это реальная сделка.

Ответ 2

Это обычная программа, которую я написал некоторое время назад для встроенной системы, которая генерировала различные подозрительные шаблоны в сети. Таким образом, он использует абсолютно никакие причудливые вещи, такие как сетевые библиотеки или даже стандартные библиотеки 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;
}

Ответ 4

Я дам решение "не хочу двух проблем":

#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 не может быть потокобезопасным (кредиты Адаму Розенфилду)

Ответ 5

Это моя попытка с очень низким уровнем программирования 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;
}//

Я надеюсь, что эта функция поможет всем вам. Опять же, учтите низкий уровень, который эта функция запрограммирована перед критикой.

Ответ 6

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

Ответ 7

inet_aton()

Ответ 8

В url/uri rfc 3986 адрес ipv4 расширенной формы Backus-Naur (ABNF) определяется как:

  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

Я выполнил проверку с помощью регулярного выражения в следующей форме:

// 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 ")"

Ответ 9

Мне нужно было выяснить, будет ли входящая строка "содержать" действительный 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;
   }
}

Ответ 10

Сделайте это с нуля так. Этот код содержит инструменты для проверки, содержит ли строка 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 версии 4. IsIp6str (char * str), если строка содержит адресный адрес версии 6.

Функции IsIp4str (char * str) и IsIp6str (char * str) возвращает true, если строка str содержит IP-адрес или false, если строка str не содержит IP-адрес.

Если вам нужна проверка, содержит ли строка IPv6-формат IP-адреса, он может выполнить функцию int IsIp6str (char * str). Он работает так же, как

Ответ 11

Вот начало функции, над которой я работал, хотя и не завершен, это может вызвать идеи или комментарии. Мысль за функцией:

  • Проверяемый переданный char указатель или строка - это адрес IPv4 без порта, используя его минимальный/максимальный размер, количество точек в строке и если символ двоеточия: существует или нет.
  • Если строка не является 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 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

Каков максимальный номер сетевого порта TCP/IP, допустимый для IPv4?

Ответ 12

//  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..
}

Ответ 13

Я изменяю один из ответов, чтобы сделать его более полным, и прилагаю весь код (включая тест).

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

Ответ 14

Я думаю, что ниже фрагмент кода 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;
}

Ответ 15

inet_addr() намного лучше, чем inet_aton() для представления нотации с номером и точкой. Проверка IP-адреса IPv4.