验证/识别字符串表示的IP地址的版本

时间:2011-11-21 13:47:51

标签: c++ c unix network-programming ip

是否有一种聪明/棘手的方法来分析表示IP地址的字符串是否有效并识别其版本,以便能够将其转换为适当的结构,只需使用UNIX API?

我不想使用正则表达式,不需要为其他库添加依赖关系。


我的第一个方法是:

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 个答案:

答案 0 :(得分:4)

根据manual page"a""a.b""a.b.c"等字符串都是inet_aton的有效地址。如果您只想要“正常”点分十进制,请对这些地址使用inet_pton

答案 1 :(得分:3)

如果您对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

答案 2 :(得分:0)

这应该有效:

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

答案 3 :(得分:0)

我在一个项目中解决了这个问题。首先,我制作了ip-addresses的EBNF,然后创建了算法。它的工作原理很好,并没有使用任何外国图书馆。 你必须调用方法CheckWholeIp并将其交给ip-string(例如:CheckWholeIp(&#34; 127.0.0.1&#34;)。如果它适合ipv4方案,它将返回int 0,如果它适合ipv4方案则返回0它不是。但值得注意的是,127.055.008.001这样的地址也会被接受。没有必要过滤前面的零。 让我知道你的想法;)

cpp文件:

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

};