Confirm / Recognize the version of the string represented by the IP address

Is there a smart / tricky way to parse if the string representing the IP address is valid and recognizes its version in order to be able to convert it to the appropriate structure simply using the UNIX API?

I do not want to use regular expression, I do not need to add dependencies to additional libraries.


My first approach:

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; 

The problem is that if I pass the string as 1 , it is successfully converted to IPv4. String type 11111 also converted to IPv4. According to the documentation:

inet_aton () returns a non-zero value if the address is valid, zero if not.

Obviously, this function not only recognizes the format XXX.XXX.XXX.XXX , but also does something more internally.

Of course, I can write my own function (and it will be fun, actually) by analyzing the string, but instead I wanted to use existing and proven functions. Is this possible, or should I write my own?

+4
source share
4 answers

According to the man page, strings such as "a" , "ab" and "abc" are valid addresses for inet_aton . If you only need a β€œnormal” dotted decimal, use inet_pton for these addresses.

+4
source

If you are open to Boost libraries, check out Boost Asio

The boost::asio::ip::address class is very good at parsing IPv6 and IPv4 addresses and bumps trying to find regular expressions, etc. to confirm the entry. It is also a cross platform.

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

Fingerprints:

 $ 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 
+3
source

This should work:

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

I solved this problem once in a project. First I created EBNF ip addresses, and then I created an algorithm. It works great and does not use any foreign libraries. You must call the CheckWholeIp method and pass it an ip string (example: CheckWholeIp ("127.0.0.1"). It will return int 0 if it fits into the ipv4 scheme, and 1 if it is not. But this is imortand note that addresses like 127.055.008.001 will also be accepted. There was no need to filter the previous zeros. Let me know your thoughts;)

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

Title:

  #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
source

Source: https://habr.com/ru/post/1382278/


All Articles