mirror of
https://github.com/openappsec/openappsec.git
synced 2025-06-28 16:41:02 +03:00
129 lines
3.7 KiB
C++
Executable File
129 lines
3.7 KiB
C++
Executable File
#include "cidrs_data.h"
|
|
|
|
#include "log_generator.h"
|
|
|
|
using namespace std;
|
|
|
|
USE_DEBUG_FLAG(D_NGINX_ATTACHMENT_PARSER);
|
|
|
|
|
|
bool
|
|
CIDRSData::matchCidr(const in_addr &address, const in_addr &network) const
|
|
{
|
|
if (network_bits == 0) {
|
|
// C99 6.5.7 (3): u32 << 32 is undefined behaviour
|
|
return true;
|
|
}
|
|
return !((address.s_addr ^ network.s_addr) & htonl(0xFFFFFFFFu << (32 - network_bits)));
|
|
}
|
|
|
|
bool
|
|
CIDRSData::matchCidr(const in6_addr &address, const in6_addr &network) const
|
|
{
|
|
#ifdef __linux__
|
|
const uint32_t *a = address.s6_addr32;
|
|
const uint32_t *n = network.s6_addr32;
|
|
#else
|
|
const uint32_t *a = address.__u6_addr.__u6_addr32;
|
|
const uint32_t *n = network.__u6_addr.__u6_addr32;
|
|
#endif
|
|
int bits_whole, bits_incomplete;
|
|
bits_whole = network_bits >> 5; // number of whole u32
|
|
bits_incomplete = network_bits & 0x1F; // number of bits in incomplete u32
|
|
if (bits_whole) {
|
|
if (memcmp(a, n, bits_whole << 2)) {
|
|
return false;
|
|
}
|
|
}
|
|
if (bits_incomplete) {
|
|
uint32_t mask = htonl((0xFFFFFFFFu) << (32 - bits_incomplete));
|
|
if ((a[bits_whole] ^ n[bits_whole]) & mask) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
CIDRSData::CIDRSData(const string &str_cidr)
|
|
{
|
|
size_t processed_bits = 0;
|
|
|
|
size_t pos = str_cidr.find_last_of('/');
|
|
|
|
// get ip from targetCidr
|
|
string str_prefix = pos != string::npos ? str_cidr.substr(0, pos) : str_cidr;
|
|
// get subnet mask from targetCidr or calculate it based on ipv4 / ipv6
|
|
string str_suffix;
|
|
if (pos != string::npos && (pos + 1) <= str_cidr.size()) {
|
|
str_suffix = str_cidr.substr(pos + 1);
|
|
} else if (str_cidr.find(':') == string::npos) {
|
|
str_suffix = "32";
|
|
} else {
|
|
str_suffix = "128";
|
|
}
|
|
|
|
|
|
int bits = -1;
|
|
try {
|
|
bits = stoi(str_suffix, &processed_bits);
|
|
network_bits = (uint8_t)bits;
|
|
// convert int to uint8_t
|
|
} catch (...) {
|
|
dbgWarning(D_NGINX_ATTACHMENT_PARSER)
|
|
<< "Failed to convert CIDR number of bits from string to int"
|
|
<< str_cidr;
|
|
return;
|
|
}
|
|
|
|
// check if CIDR is valid
|
|
if (processed_bits != str_suffix.length() || bits > 128 || bits < 0) {
|
|
dbgWarning(D_NGINX_ATTACHMENT_PARSER)
|
|
<< "Failed to convert CIDR number of bits from string to int (out of range)."
|
|
<< str_cidr;
|
|
return;
|
|
}
|
|
|
|
if (IPAddr::isValidIPAddr(str_prefix)) {
|
|
ip_addr = IPAddr::createIPAddr(str_prefix).unpack();
|
|
} else {
|
|
dbgDebug(D_NGINX_ATTACHMENT_PARSER) << "Failed to convert CIDR number of bits from string to int";
|
|
return;
|
|
}
|
|
|
|
dbgDebug(D_NGINX_ATTACHMENT_PARSER) << "successfully created cidr from the following string: " << str_cidr;
|
|
valid_cidr = true;
|
|
}
|
|
|
|
bool
|
|
CIDRSData::contains(const string &source_ip) const
|
|
{
|
|
if(!valid_cidr) {
|
|
dbgDebug(D_NGINX_ATTACHMENT_PARSER) << "Invalid CIDR.";
|
|
return false;
|
|
}
|
|
|
|
// check from which type the target ip and check if ip belongs to is mask ip
|
|
//convert source_ip to ip v4 or v6.
|
|
switch (ip_addr.getType()) {
|
|
case IPType::V4: {
|
|
struct in_addr source_inaddr;
|
|
if (inet_pton(AF_INET, source_ip.c_str(), &source_inaddr) == 1) {
|
|
return matchCidr(source_inaddr, ip_addr.getIPv4());
|
|
}
|
|
break;
|
|
}
|
|
case IPType::V6: {
|
|
struct in6_addr source_inaddr6;
|
|
if (inet_pton(AF_INET6, source_ip.c_str(), &source_inaddr6) == 1) {
|
|
return matchCidr(source_inaddr6, ip_addr.getIPv6());
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
dbgWarning(D_NGINX_ATTACHMENT_PARSER) << "Unexpected ip type";
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|