web-dev-qa-db-fra.com

Déterminer si une chaîne est une adresse IPv4 valide en C

Quel serait un bon moyen de déterminer si une chaîne contient une adresse IPv4? Devrais-je utiliser isdigit()

22
Mike

J'ai demandé une question similaire pour C++ . Vous devriez pouvoir utiliser une version légèrement modifiée (pour le C) de ce que j'ai créé à l'époque.

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

Vous devrez utiliser #include <arpa/inet.h> pour utiliser la fonction inet_pton () .

Mise à jour en fonction des commentaires à la question: Si vous voulez savoir si une chaîne de style C contient une adresse IP, vous devez combiner les deux réponses données jusqu'à présent. Utilisez une expression régulière pour rechercher des modèles qui correspondent approximativement à une adresse IP, puis utilisez la fonction ci-dessus pour vérifier la correspondance et voir si c'est la vraie affaire.

50
Bill the Lizard

C’est une routine que j’écrivais il ya quelque temps pour un système intégré qui générait divers modèles suspects sur un réseau. En tant que tel, il utilise absolument no des éléments fantaisistes tels que des bibliothèques réseau ou même les bibliothèques C standard, préférant éviter tout ce qui est moderne, comme les bibliothèques de symboles de chaîne et de (frémissement) expressions régulières: adapté à à peu près n'importe quel environnement dans lequel vous pourriez vous trouver, et c'était incroyablement rapide.

Cependant, si vous êtes dans un environnement qui a quelque chose comme checkIp4Addess(), je vous suggérerais de l’utiliser plutôt. C'est une indication des choses que vous devez parfois supporter lorsque vous faites des choses incorporées (bien que ce soit soit une vraie solution).

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;
}
7
paxdiablo
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;
}
1
deepmax

C’est mon essai avec une programmation C de très faible niveau (actuellement utilisée dans l’un de mes programmes pour un microcontrôleur PIC) . Elle n’utilise pas la bibliothèque string.h . Elle n’utilise pas de pointeurs, car ce compilateur J'utilise ne fonctionne pas bien avec eux, de toute façon vous pourriez les utiliser . En tenant compte de cela et en définissant une variable pour gérer le tampon de données entrant comme ceci:

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

J'espère que cette fonction vous aidera tous ... Encore une fois, tenez compte du faible niveau de programmation de cette fonction avant de le critiquer.

1
Dilandau

J'utiliserais cette expression régulière (courtoisie de Exemples d'expressions régulières ):

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

Je vais donner la solution "ne veulent pas deux problèmes":

#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 peut ne pas être thread-safe (crédit à Adam Rosenfield)

1
Tom
//  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
Colin B Maharaj

Dans l’URL/URI RFC 3986, l’adresse ipv4 de la forme de Backus-Naur augmentée (ABNF) est définie comme suit:

  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

J'ai implémenté le contrôle avec l'expression rationnelle sous la forme suivante:

// 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
piotr

Faites-le à partir de zéro comme ça. Ce code contient des outils pour vérifier si la chaîne contient une adresse IP IPv4. 

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

Fonction IsIp4str (char * str) teste si la chaîne contient le format d'adresse à quatre adresses IP. IsIp6str (char * str) test de la fonction si la chaîne contient le format d'adresse à six adresses IP.

Fonctions IsIp4str (char * str) et IsIp6str (char * str) renvoie true si la chaîne str contient l'adresse IP ou false si la chaîne str ne contient pas l'adresse IP. 

Si vous avez besoin de vérifier si la chaîne contient le format d'adresse IP IPv6, vous pouvez utiliser la fonction IsIp6str (char * str). Cela fonctionne de la même manière que 

0
user3896692

Je modifie une des réponses pour la rendre plus complète et attache tout le code (inclure 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
user7469511

J'avais besoin de savoir si la chaîne entrante "contient" une adresse IP valide et de renvoyer un pointeur sur la partie de la chaîne entrante qui correspond à l'adresse IP valide, le cas échéant. Sinon, retourne un pointeur nul.

Voici du code qui semble fonctionner, bien que pas encore testé, je l’ai écrit et j’ai essayé rapidement. Je n'ai pas encore ajouté de contrôle pour limiter les nombres à des valeurs sur un octet, mais assurez-vous qu'ils sont limités à trois chiffres. 

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
jillybean_64

Voici le début d’une fonction sur laquelle j’ai travaillé, même si elle n’est pas complète, elle peut susciter des idées ou des commentaires. La pensée derrière la fonction est;

  1. Vérifiez que le pointeur ou la chaîne de caractères transmise est une adresse IPv4 sans port utilisant sa taille minimale/maximale, le nombre de points de la chaîne et le caractère deux-points: existant ou non. 
  2. Si la chaîne n'est pas IPv4 avec ou sans port, vérifiez si la chaîne est IPv6. Si ce n'est pas IPv6, le format IP n'est pas reconnu car il n'a pas encore été mis en œuvre.

Je pense que cela dépend de la profondeur avec laquelle vous voulez aborder le problème, de la profondeur avec laquelle vous voulez comprendre les problèmes qui pourraient survenir. 

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

}

Interconnexion TCP/IP

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

Le manuel Cisco Internetworking http://docwiki.Cisco.com/wiki/Internetworking_Technology_Handbook

Modèle de référence de l'interconnexion de systèmes ouverts http://docwiki.Cisco.com/wiki/Internetworking_Basics#Open_Systems_Interconnection_Reference_Model

Dépannage de Cisco sur les réseaux TCP/IP https://www.Cisco.com/en/US/docs/internetworking/troubleshooting/guide/tr1907.pdf

Quel est le plus grand numéro de port réseau TCP/IP autorisé pour IPv4?

0
user1687619