#2 Added function to check if an IP is private (f.ex. 192.168.1.1) or not. Added functions to read the computer's own IP address and gateway IP address. Missing Windows implementation for that.

master
Tomatix 3 years ago
parent 60768be2ce
commit 4bfc9b2380
  1. 186
      IRCClient/Utilities.cpp
  2. 3
      IRCClient/Utilities.h

@ -8,9 +8,56 @@
#include "Utilities.h"
#include <fmt/format.h>
#include <cstdint>
#include <cstdio>
#include <sstream>
#include <vector>
namespace {
constexpr auto DefaultIpAddress{ "127.0.0.1" };
uint32_t ipStrToInt(const std::string& ip)
{
std::stringstream ss(ip);
std::string p;
std::vector<unsigned> parts;
while (getline(ss, p, '.'))
parts.emplace_back(std::stoul(p));
uint32_t ret = parts[0];
for (int i = 1; i < 4; ++i) {
ret <<= 8u;
ret |= parts[i];
}
return ret;
}
std::string getIpFromSecondToken(const std::string& input)
{
if (input.empty())
return {};
/*
* Simple shell injection check, input is likely to come from a popen() (shell) call.
* There is no way to tell if the called program has been tampered with...
*/
auto it = std::find_if(begin(input), end(input),
[](char c) {
return c == '|' || c == '&' || c == ';' || c == '$';
});
if (it != input.end())
return DefaultIpAddress; // someone's fooling around with 'ip' command, let's not continue...
else {
auto start = input.find(' ') + 1;
auto len = input.find(' ', start);
if (len != std::string::npos)
len -= start;
return input.substr(start, len);
}
}
} // anonymous namespace
std::pair<std::string,std::string> FormatCTCPLine(std::string line)
{
/* Clean away the CTCP byte flags */
@ -97,19 +144,7 @@ std::string longIpToNormal(const std::string& longip)
std::string normalIpToLong(const std::string& normalip)
{
std::stringstream ss(normalip);
std::string p;
std::vector<unsigned> parts;
while (getline(ss, p, '.'))
parts.emplace_back(std::stoul(p));
uint32_t ret = parts[0];
for (int i = 1; i < 4; ++i) {
ret <<= 8u;
ret |= parts[i];
}
return std::to_string(ret);
return std::to_string(ipStrToInt(normalip));
}
std::string concatenateModes(const std::unordered_map<char, std::string>& modes)
@ -193,3 +228,128 @@ std::string toBase64(const std::string& input)
return ret;
}
std::string findOwnIpAddress()
{
std::string ipaddr{ DefaultIpAddress };
#if defined(__linux__) || defined(__linux)
std::string iface;
{
char buf[64]{};
// This command will return either empty or something like "dev eth0 some more data here" - we want the eth0 part.
auto fd = popen(R"(ip route show default | grep -E -o 'dev\s.+(\s|$)')", "r");
auto readres = fgets(buf, sizeof(buf), fd);
pclose(fd);
if (!readres)
return ipaddr;
iface.assign(buf, sizeof(buf));
iface = getIpFromSecondToken(iface);
}
if (!iface.empty()) {
char buf[64]{};
// This command will match either empty or exactly "inet 123.45.67.89" though with a proper IP address.
static constexpr auto regex{ R"(inet\s[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3})" };
const auto cmd{ fmt::format("ip address show {} | grep -E -o '{}'", iface, regex) };
auto fd = popen(cmd.c_str(), "r");
auto readres = fgets(buf, sizeof(buf) - 1, fd);
pclose(fd);
if (!readres)
return ipaddr;
// We use strlen() since buf will hold many zero-bytes and popen() doesn't give us a size.
ipaddr.assign(buf, strlen(buf));
auto start = ipaddr.find(' ') + 1;
ipaddr = ipaddr.substr(start);
if (ipaddr.back() == '\n')
ipaddr.erase(ipaddr.end() - 1);
}
#elif defined(WI32) || defined(WIN64)
return "127.0.0.1"; // TODO
#else
#error Unsupported platform, implementation of findOwnIpAddress() missing!
#endif
return ipaddr.empty() ? DefaultIpAddress : ipaddr;
}
std::string findOwnGatewayIpAddress()
{
std::string ipaddr{ DefaultIpAddress };
#if defined(__linux__) || defined(__linux)
std::string gateway;
{
char buf[64]{};
// This command will return either empty or something like "via 10.0.0.1 some more data here" - we want the 10.0.0.1 part.
auto fd = popen(R"(ip route show default | grep -E -o 'via\s.+(\s|$)')", "r");
auto readres = fgets(buf, sizeof(buf), fd);
pclose(fd);
if (!readres)
return ipaddr;
gateway.assign(buf, sizeof(buf));
ipaddr = getIpFromSecondToken(gateway);
}
#elif defined(WI32) || defined(WIN64)
return "127.0.0.1"; // TODO
#else
#error Unsupported platform, implementation of findOwnIpAddress() missing!
#endif
return ipaddr.empty() ? DefaultIpAddress : ipaddr;
}
bool isPrivateIp(const std::string& ip)
{
/*
* Class A: 10.0.0.0 - 10.255.255.255
* Class B: 172.16.0.0 - 172.31.255.255
* Class C: 192.168.0.0 - 192.168.255.255
*/
const auto intip{ ipStrToInt(ip) };
const auto classIp{ (intip & 0xFF000000) >> 24 };
/* Class A */
if (classIp == 10) {
// All addresses starting on "10." is in fact private.
return true;
}
/* Class B */
else if (classIp == 172) {
// Check if second byte is between 16 and 31.
const auto num = (intip & 0x00FF0000) >> 16;
return (num >= 16 && num <= 31);
}
/* Class C */
else if (classIp == 192) {
// Check if second byte is exactly 168.
return ((intip & 0x00FF0000) >> 16) == 168;
}
/* Not in any of the classes, not a private IP. */
else {
return false;
}
}

@ -21,5 +21,8 @@ std::string normalIpToLong(const std::string& normalip);
std::string concatenateModes(const std::unordered_map<char, std::string>& modes);
bool strEquals(const std::string& l, const std::string& r);
std::string toBase64(const std::string& input);
std::string findOwnIpAddress();
std::string findOwnGatewayIpAddress();
bool isPrivateIp(const std::string& ip);
#endif //IRCUTILITIES_H

Loading…
Cancel
Save