Проверить / распознать версию строки представленного IP-адреса - PullRequest
4 голосов
/ 21 ноября 2011

Есть ли умный / хитрый способ проанализировать, является ли представленный в строке IP-адрес действительным, и распознать его версию, чтобы можно было преобразовать его в соответствующую структуру, просто используя API UNIX?

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


Мой первый подход был следующим:

in_addr addr;
memset( &addr, 0, sizeof( in_addr ) );
// try to convert from standard numbers-and-dots notation into binary data
if( 0 != inet_aton( sIPAddress.c_str(), &addr ) )
{
    return Socket::enIPv4;      // valid IPv4
}

in6_addr addr6;
memset( &addr6, 0, sizeof( in6_addr ) );
if( inet_pton( AF_INET6, sIPAddress.c_str(), &addr6 ) > 0 )
{
    return Socket::enIPv6;      // valid IPv6
}

return Socket::enUnknown;

Проблема здесьчто если я передам строку типа 1, она успешно преобразуется в IPv4.Строка типа 11111 также конвертируется в IPv4.По документации:

inet_aton () возвращает ненулевое значение, если адрес действителен, ноль - если нет.

Очевидно, что эта функция распознает не только формат XXX.XXX.XXX.XXX,но делает что-то более внутреннее.

Конечно, я могу написать свою собственную функцию (и на самом деле это будет весело), ​​анализируя строку, но вместо этого я хотел использовать уже существующие и протестированные функции.Это возможно, или я должен написать свой собственный?

Ответы [ 4 ]

4 голосов
/ 21 ноября 2011

Согласно справочной странице , строки типа "a", "a.b" и "a.b.c" являются действительными адресами для inet_aton.Если вам нужен только "обычный" десятичный разделитель, используйте inet_pton и для этих адресов.

3 голосов
/ 21 ноября 2011

Если вы открыты для библиотек Boost, посмотрите Boost Asio

Класс boost::asio::ip::address очень хорош при анализе адресов IPv6 и IPv4, а также при попытках найти регулярные выражения и тому подобное для проверки ввода. Это также кроссплатформенная.

#include <boost/asio.hpp>
#include <boost/assert.hpp>

#include <iostream>
#include <string>

using namespace std;

int main(int argc, char* argv[]){

    std::string ipv4("192.168.1.1");
    std::string ipv6("::1");
    std::string notIP("1");

    boost::asio::ip::address ipv4Addr = boost::asio::ip::address::from_string(ipv4);
    BOOST_ASSERT(ipv4Addr.is_v4() == true);

    boost::asio::ip::address ipv6Addr = boost::asio::ip::address::from_string(ipv6);
    BOOST_ASSERT(ipv6Addr.is_v6() == true);

    boost::asio::ip::address badAddr;
    try{
        badAddr = boost::asio::ip::address::from_string(notIP);
    }
    catch(const std::exception& e){
        std::cout << "Bad Address:  " << e.what() << std::endl;
    }   

    return 0;
}

Это печатает:

$ g++ -Wall -I/usr/local/boost-1.47.0/include/ -L/usr/local/boost-1.47.0/lib -o ./asioTestIP ./asioTestIP.cpp -lboost_system
$ ./asioTestIP 
Bad Address:  Invalid argument
0 голосов
/ 20 апреля 2016

Я решил эту проблему один раз в проекте.Сначала я сделал EBNF ip-адресов, а затем создал алгоритм.Работает нормально и не использует никаких иностранных библиотек.Вы должны вызвать метод CheckWholeIp и передать ему ip-строку (пример: CheckWholeIp ("127.0.0.1"). Он вернет int 0, если он вписывается в схему ipv4, и 1, если это не так. Но это важно дляобратите внимание, что такие адреса, как 127.055.008.001, также будут приняты. Не было необходимости фильтровать вышеупомянутые нули. Дайте мне знать ваши мысли;)

cpp file:

    #include "CheckIp.h"

CheckIp::CheckIp()
{
}

int CheckIp::CheckWholeIp(string s)
{

    int size = s.size();
    int psum = 0;
    //check amount of points
    for (int i = 0; i <= size; i++) {
        if (s[i] == '.')psum++;
    }
    if (psum != 3)return 1;

    //write stringblocks
    string sbl0 = "";
    string sbl1 = "";
    string sbl2 = "";
    string sbl3 = "";
    int ii = 0;

    while (s[ii] != '.') {
        sbl0 = sbl0 + s[ii];
        ii++;
    }
    ii++;
    while (s[ii] != '.') {
        sbl1 = sbl1 + s[ii];
        ii++;
    }
    ii++;
    while (s[ii] != '.') {
        sbl2 = sbl2 + s[ii];
        ii++;
    }
    ii++;
    while (s[ii] != NULL) {
        sbl3 = sbl3 + s[ii];
        ii++;
    }

    //checking the blocks
    if (CheckBlock(sbl0) == 1 | CheckBlock(sbl1) == 1 | CheckBlock(sbl2) == 1 | CheckBlock(sbl3) == 1) return 1;

    return 0;
}

int CheckIp::CheckBlock(string s)
{
    int sizeb = s.size();
    //checking size of block
    if (sizeb > 3) return 1;
    string ss;
    for (int i = 0; i < sizeb; i++) {
        ss = s[i];
        if (CheckNumber(ss) == 1) return 1;
    }

    return 0;
}

int CheckIp::CheckNumber(string s)
{
    if (s == "0" | s == "1" | s == "2" | s == "3" | s == "4" | s == "5" | s == "6" | s == "7" | s == "8" | s == "9") {
        return 0;
    }
    else {
        return 1;
    }

}

Заголовок:

    #pragma once
#include <string>

using namespace std;

ref class CheckIp
{
public:
    CheckIp();

    static int CheckWholeIp(string s);

private: static int CheckBlock(string s);

        static int CheckNumber(string s);

};
0 голосов
/ 21 ноября 2011

Это должно работать:

#include <iostream>
#include <string>
#include <vector>
#include <stdlib.h>

void printError(const std::string& errStr) {
    std::cerr << errStr << std::endl;
}

bool checkAddress(const std::string& address) {
    std::vector<std::string> arr;
    int k = 0;
    arr.push_back(std::string());
    for (std::string::const_iterator i = address.begin(); i != address.end(); ++i) {
        if (*i == '.') {
            ++k;
            arr.push_back(std::string());
            if (k == 4) {
                printError("too many '.'");
            }
            continue;
        }
        if (*i >= '0' && *i <= '9') {
            arr[k] += *i;
        } else {
            printError("wrong character");
            return false;
        }
        if (arr[k].size() > 3) {
            printError("size exceeded");
            return false;
        }
    }
    if (k != 3) {
        printError("not enough '.'");
        return false;
    }
    for (int i = 0; i != 4; ++i) {
        const char* nPtr = arr[i].c_str();
        char* endPtr = 0;
        const unsigned long a = ::strtoul(nPtr, &endPtr, 10);
        if (nPtr == endPtr) {
            printError("invalid numeric input");
            return false;
        }
        if (a > 255) {
            printError("out of range");
            return false;
        }
    }
    return true;
}

int main(int argc, char* argv[]) {
    if (argc < 2) {
        return -1;
    }
    std::string address = argv[1];
    if (checkAddress(address)) {
        std::cout << "address ok" << std::endl;
    } else {
        std::cout << "bad address" << std::endl;
    }
    return 0;
}
...