web-dev-qa-db-fra.com

Comment valider qu'une chaîne est une adresse IPv4 valide en C++?

Je n'ai pas besoin de valider que l'adresse IP est accessible ou quelque chose comme ça. Je veux juste valider que la chaîne est au format IPv4 en pointillés (xxx.xxx.xxx.xxx), où xxx est compris entre 0 et 255.

43
Bill the Lizard

Vous voulez probablement le inet_pton , qui renvoie -1 pour l'argument AF non valide, 0 pour l'adresse invalide et +1 pour l'adresse IP valide. Il prend en charge les adresses IPv4 et futures IPv6. Si vous avez toujours besoin d'écrire votre propre traitement d'adresse IP, n'oubliez pas qu'un numéro hexadécimal standard 32 bits est une adresse IP valide. Toutes les adresses IPv4 ne sont pas en notation décimale à points. 

Cette fonction vérifie l'adresse et vous permet également d'utiliser la même adresse dans les appels de socket associés. 

50
Raymond Martineau

Boost.Asio fournit la classe ip :: address . Si vous voulez juste vérifier la chaîne, vous pouvez l'utiliser comme ceci:

std::string ipAddress = "127.0.0.1";
boost::system::error_code ec;
boost::asio::ip::address::from_string( ipAddress, ec );
if ( ec )
    std::cerr << ec.message( ) << std::endl;

Cela fonctionne également pour les quads hexadécimaux et octaux. C'est aussi une solution beaucoup plus portable.

44
Björn Pollex

La solution sur laquelle je me suis installée était:

bool Config::validateIpAddress(const string &ipAddress)
{
    struct sockaddr_in sa;
    int result = inet_pton(AF_INET, ipAddress.c_str(), &(sa.sin_addr));
    return result != 0;
}

Cela fonctionne pour la plupart des cas mentionnés dans d'autres réponses. Il ne reconnaît pas les adresses IP avec un format octal ou hexadécimal, mais c'est acceptable pour mon application.

33
Bill the Lizard

Cela a l'air d'une simplicité trompeuse, mais présente quelques pièges. Par exemple, beaucoup des solutions présentées dans les réponses précédentes supposent que les quads sont en base 10 - mais un quad commençant par un zéro doit être traité comme un nombre base 8 (octal), d’où par exemple une partie de quad commençant par zéro et contenant les chiffres 8 ou 9 n'est pas valide. Ainsi, le numéro IP 192.168.1.010 est non192.168.1.10 mais en réalité est 192.168.1.8 et le numéro IP 192.168.019.14 n'est pas valide, car le troisième quadrilatère contient le chiffre 8 de base 9 non valide de la base.

Je vous encourage vivement à utiliser les fonctions fournies par la bibliothèque de sockets incluse dans votre système d'exploitation ou dans l'environnement du compilateur.

Edit: (Je pensais que c'était implicite, mais) bien sûr, vous pouvez aussi avoir des quads hexadécimaux, à la 192.168.1.0x0A pour 192.168.1.10, et bien sûr, vous pouvez mélanger votre contenu sadique en utilisant des majuscules et des minuscules, à la 0xC0.0xa8.1.010 pour 192.168.1.8. Essayez quelques exemples en utilisant ping si vous voulez vous amuser. Cela fonctionne parfaitement entre plusieurs plates-formes (testé il y a un certain temps en jurant sous Linux, NetBSD et Win32.)

Nouvelle modification en réponse à la demande de KaluSingh Gabbar: Par exemple, vous pouvez spécifier 192.168.1.10 en tant que 0xc0a8010a et il représente toujours un numéro IP valide, à la:

[mihailim@home ~]$ ping 0xc0a8010a
PING 0xc0a8010a (192.168.1.10) 56(84) bytes of data.
^C
--- 0xc0a8010a ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2479ms
17
Mihai Limbășan

Voici une méthode simple. 

bool IsIPAddress(std::string & ipaddr)
    {    

    StringTokenizer quads(ipaddr,".");

    if (quads.countTokens() != 4) return false;

    for (int i=0; i < 4; i++)
      {
      std::string quad = quads.nextToken();
      for (int j=0; j < quad.length(); j++
         if (!isdigit(quad[j])) return false;

      int quad = atoi(quads.GetTokenAt(i));
      if (quad < 0) || (quad > 255)) return false;
      }

    return true;
    }
8
Steve

Si vous êtes sur Windows, vous pouvez utiliser WSAStringToAddress et basé sur la valeur de retour que nous connaissons, si l'argument passé est IP valide ou non. Cela prend en charge à la fois IPv4 et IPv6 à partir de Windows 2000.

5
user1740538

Voici le programme C pour valider une adresse IPV4 donnée. J'ai supposé que l'adresse IP est au format décimal. S'il vous plaît donnez-moi vos pensées à ce sujet.

  // strTokenFunction.cpp : Check if the specified address is a valid numeric IP address.
  // This function is equavalent to the IPAddress.TryParse() method in C#

#include "stdafx.h"
#include <stdio.h>
#include <conio.h>
#include <string.h>

bool isValidIpAddress(char *st)
{
    int num, i, len;
    char *ch;

    //counting number of quads present in a given IP address
    int quadsCnt=0;

    printf("Split IP: \"%s\"\n", st);

    len = strlen(st);

    //  Check if the string is valid
    if(len<7 || len>15)
        return false;

    ch = strtok(st, ".");

    while (ch != NULL) 
    {
        quadsCnt++;
        printf("Quald %d is %s\n", quadsCnt, ch);

        num = 0;
        i = 0;

        //  Get the current token and convert to an integer value
        while(ch[i]!='\0')
        {
            num = num*10;
            num = num+(ch[i]-'0');
            i++;
        }

        if(num<0 || num>255)
        {
            printf("Not a valid ip\n");
            return false;
        }

        if( (quadsCnt == 1 && num == 0) || (quadsCnt == 4 && num == 0))
        {
            printf("Not a valid ip, quad: %d AND/OR quad:%d is zero\n", quadsCnt, quadsCnt);
            return false;
        }

        ch = strtok(NULL, ".");
    }

    //  Check the address string, should be n.n.n.n format
    if(quadsCnt!=4)
    {
        return false;
    }

    //  Looks like a valid IP address
    return true;
}

int main() 
{
    char st[] = "192.255.20.30";
    //char st[] = "255.255.255.255";
    //char st[] = "0.255.255.0";

    if(isValidIpAddress(st))
    {
        printf("The given IP is a valid IP address\n"); 
    }
    else
    {
        printf("The given IP is not a valid IP address\n");
    }
}
2
Savi

Boost.Regex serait approprié.

bool validate_ip_address(const std::string& s)
{
   static const boost::regex e("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}");
   return regex_match(s, e);
}
2
Martin Cote

Si vous voulez écrire vous-même plutôt que d'utiliser une bibliothèque, alors

atoi () pour convertir des caractres en entiers vous permettra de tester la plage de chaque numero, ainsi que certains strcmp entre les ".". Vous pouvez également effectuer quelques vérifications rapides, telles que la longueur de la chaîne (doit comporter moins de 16 caractères (sans le caractère de fin, caractère null), le nombre de points, etc.

Mais, il est probablement beaucoup plus facile d'utiliser le code existant.

2
xan

J'ai fait la même chose en utilisant seulement les fonctions C stdlib bien qu'il ne supporte pas les quads octaux comme mentionné ci-dessus, mais cela ne devrait pas être un problème, je peux facilement ajouter cette partie et vous la donner. En tant que débutant (étudiant), je ne savais même pas qu’il était possible d’obtenir un nombre octal dans votre IP. Je pensais que ce devait être une décimale.

2
Ramadheer Singh

quelques corrections mineures pour résoudre certains cas comme 127..0.1, 127.0.0 .. et supprimer des espaces si ont:




    #include <iostream>
    #include <vector>
    #include <string>
    #include <sstream>
    #include <algorithm>
    #include <iterator>
    #include <stdio.h>

    using namespace std;

    vector split(char* str, char delimiter)
    {
        const string data(str);
        vector elements;
        string element;
        for(int i = 0; i  0) {//resolve problem: 127.0..1
                    elements.Push_back(element);
                    element.clear();
                }
            }
            else if (data[i] != ' ')
            {
                element += data[i];
            }

        }
        if (element.length() > 0)//resolve problem: 127.0..1
            elements.Push_back(element);
        return elements;
    }

    bool toInt(const string& str, int* result)
    {
        if (str.find_first_not_of("0123456789") != string::npos)
            return false;

        stringstream stream(str);
        stream >> *result; // Should probably check the return value here
        return true;
    }

    /** ipResult: the good ip address, e.g. spaces are removed */
    bool validate(char* ip, string *ipResult)
    {
        const static char delimiter = '.';
        const vector parts = split(ip, delimiter);
        *ipResult = "";
        if (parts.size() != 4)
            return NULL;

        for(int i = 0; i  255)
                return NULL;

            if (i == 3) {
                *ipResult += parts[i];
            } else {
                *ipResult += (parts[i] +".");
            }

        }
        return true;
    }

    int main()
    {
        string ip;
        printf("right %d\n", validate("127.0.0.1", &ip));
        printf("good ip: %s\n", ip.c_str());
        printf("wrong %d\n", validate("127.0.0.-1", &ip));
        printf("good ip: %s\n", ip.c_str());
        printf("wrong %d\n", validate("127..0.1", &ip));
        printf("good ip: %s\n", ip.c_str());
        printf("wrong %d\n", validate("...0.1", &ip));
        printf("good ip: %s\n", ip.c_str());
        printf("wrong %d\n", validate("127.0.0.", &ip));
        printf("good ip: %s\n", ip.c_str());
        printf("right %d\n", validate("192.168.170.99", &ip));
        printf("good ip: %s\n", ip.c_str());
        printf("right %d\n", validate("127.0 .0  .1", &ip));
        printf("good ip: %s\n", ip.c_str());
        printf("\n");

        system("pause");

        return 0;
    }

1
user2314327

Vous pouvez accomplir cela très facilement avec boost tokenizer et boost char_separator.

http://www.boost.org/doc/libs/1_37_0/libs/tokenizer/char_separator.htm

1
Marcin

Si vous ne voulez pas les frais généraux de Boost ou TR1, vous pouvez rechercher les points et vérifier si les caractères entre eux sont des nombres de 0 à 255.

1
EricSchaefer

Vous pouvez écrire votre propre fonction comme ceci:

bool isValidIPv4(const char *IPAddress)
{
   unsigned char a,b,c,d;
   return sscanf(IPAddress,"%d.%d.%d.%d", &a, &b, &c, &d) == 4;
}

sscanf() et sprintf() sont très utiles dans certaines situations. :))

1
Kim Ninh
vector<string> &split(const string &s, char delim, vector<string> &elems) {
    stringstream ss(s);
    string item;
    while(getline(ss, item, delim)) {
       elems.Push_back(item);
    }
    return elems;
}

vector<string> split(const string &s, char delim) {
   vector<string> elems;
   return split(s, delim, elems);
}


bool isIPAddress(string  ipaddr){

    if (ipaddr.length()){
            vector<string> _ip=split(ipaddr,'.');
            if (_ip.size()==4){
                    for (int i=0; i < 4; i++){
                            for (int j=0; j < _ip[i].length(); j++)
                                    if (!isdigit(_ip[i][j])) return false;
                            if ((atoi(_ip[i].c_str()) < 0) || (atoi(_ip[i].c_str()) > 255)) return false;
                    }
            return true;
            }
    }
    return false;
 }
1
Amir

Si vous souhaitez recevoir une adresse IP sous la forme habituelle (8.8.8.8, 192.168.1.1, etc ...) .__, alors j'ai écrit le code suivant qui développe la réponse de Bjorn:

void validateIP(const std::string &IPv4_address)
{
    boost::system::error_code error_code;
    auto raw_ipv4_address = boost::asio::ip::address::from_string(IPv4_address, error_code);
    if (error_code)
    {
        throw std::invalid_argument(error_code.message());
    }

    std::string raw_to_string_form = raw_ipv4_address.to_string();
    if (raw_to_string_form.compare(IPv4_address))
    {
        throw std::invalid_argument("Input IPv4 address is invalid");
    }
}

La raison en est que si vous transmettez une adresse IP telle que 8.88.8 ou 12345 (forme décimale) , la réponse de Bjorn ne générera pas d'erreur. (au moins avec boost 1.68) Mon code convertit n'importe quel formulaire en structure interne dans Boost, puis le reconvertit en un format décimal en pointillé, nous le comparons ensuite à la première adresse IP reçue pour voir si ils sont égaux, sinon, nous savons avec certitude que l’entrée n’est pas celle que nous voulions.

0
A. Smoliak