mirror of
https://github.com/openappsec/openappsec.git
synced 2025-06-28 16:41:02 +03:00
228 lines
7.8 KiB
C++
228 lines
7.8 KiB
C++
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "gradual_deployment.h"
|
|
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <boost/algorithm/string.hpp>
|
|
|
|
#include "enum_range.h"
|
|
#include "connkey.h"
|
|
|
|
USE_DEBUG_FLAG(D_GRADUAL_DEPLOYMENT);
|
|
|
|
using namespace std;
|
|
|
|
class SetGradualDeploymentRanges : public ServerRest
|
|
{
|
|
public:
|
|
void doCall() override
|
|
{
|
|
dbgFlow(D_GRADUAL_DEPLOYMENT) << "Set gradual policy API";
|
|
|
|
auto maybe_type = convertServiceStrToAttachmentType(attachment_type.get());
|
|
if (!maybe_type.ok()) {
|
|
string error = "Failed to determine attachment type. Type: "
|
|
+ attachment_type.get()
|
|
+ ", error: "
|
|
+ maybe_type.getErr();
|
|
dbgWarning(D_GRADUAL_DEPLOYMENT) << error;
|
|
throw JsonError(error);
|
|
}
|
|
dbgTrace(D_GRADUAL_DEPLOYMENT)
|
|
<< "Setting gradual policy for attachment of type: "
|
|
<< attachment_type.get();
|
|
|
|
auto i_gradual_deployment = Singleton::Consume<I_GradualDeployment>::from<GradualDeployment>();
|
|
auto set_policy_res = i_gradual_deployment->setPolicy(maybe_type.unpackMove(), ip_ranges.get());
|
|
if (!set_policy_res.ok()) throw JsonError(set_policy_res.getErr());
|
|
|
|
return;
|
|
}
|
|
|
|
private:
|
|
C2S_PARAM(vector<string>, ip_ranges)
|
|
C2S_PARAM(string, attachment_type)
|
|
|
|
Maybe<I_GradualDeployment::AttachmentType>
|
|
convertServiceStrToAttachmentType(string &type) {
|
|
transform(type.begin(), type.end(), type.begin(), ::tolower);
|
|
if (type == "http-manager") return I_GradualDeployment::AttachmentType::NGINX;
|
|
if (type == "access-control") return I_GradualDeployment::AttachmentType::KERNEL;
|
|
|
|
return genError("unknown attachment type");
|
|
}
|
|
};
|
|
|
|
class GradualDeployment::Impl
|
|
:
|
|
Singleton::Provide<I_GradualDeployment>::From<GradualDeployment>
|
|
{
|
|
public:
|
|
void
|
|
init()
|
|
{
|
|
dbgFlow(D_GRADUAL_DEPLOYMENT) << "Initializing Gradual Deployment Manager";
|
|
|
|
auto rest = Singleton::Consume<I_RestApi>::by<GradualDeployment>();
|
|
rest->addRestCall<SetGradualDeploymentRanges>(RestAction::SET, "gradual-deployment-policy");
|
|
|
|
dbgTrace(D_GRADUAL_DEPLOYMENT) << "Gradual Deployment Manager initialization is done successfully";
|
|
}
|
|
|
|
Maybe<void>
|
|
setPolicy(I_GradualDeployment::AttachmentType type, const vector<string> &str_ip_ranges) override
|
|
{
|
|
auto maybe_policy = parseIpRanges(str_ip_ranges);
|
|
if (!maybe_policy.ok()) {
|
|
auto error = "Failed to set gradual deployment policy. Error: " + maybe_policy.getErr();
|
|
dbgWarning(D_GRADUAL_DEPLOYMENT) << error;
|
|
return genError(error);
|
|
}
|
|
|
|
ip_ranges_map[static_cast<int>(type)] = maybe_policy.unpackMove();
|
|
return Maybe<void>();
|
|
}
|
|
|
|
vector<string>
|
|
getPolicy(I_GradualDeployment::AttachmentType type) override
|
|
{
|
|
vector<string> res;
|
|
for (const IPRange &range : ip_ranges_map[static_cast<int>(type)]) {
|
|
// Range is validated on insertion
|
|
res.push_back(convertIpRangeToStr(range).unpack());
|
|
}
|
|
return res;
|
|
}
|
|
|
|
vector<IPRange> &
|
|
getParsedPolicy(I_GradualDeployment::AttachmentType type) override
|
|
{
|
|
return ip_ranges_map[static_cast<int>(type)];
|
|
}
|
|
|
|
private:
|
|
IpAddress
|
|
ConvertToIpAddress(const IPAddr &addr) {
|
|
IpAddress address;
|
|
switch (addr.getType()) {
|
|
case IPType::V4: {
|
|
address.addr4_t = addr.getIPv4();
|
|
address.ip_type = IP_VERSION_4;
|
|
break;
|
|
}
|
|
case IPType::V6: {
|
|
address.addr6_t = addr.getIPv6();
|
|
address.ip_type = IP_VERSION_6;
|
|
break;
|
|
}
|
|
default:
|
|
dbgAssert(false) << AlertInfo(AlertTeam::CORE, "gradual deployment") << "Unsupported IP type";
|
|
}
|
|
return address;
|
|
}
|
|
|
|
Maybe<IPRange>
|
|
createRangeFromStr(const string &range)
|
|
{
|
|
vector<string> temp_params_list;
|
|
boost::split(temp_params_list, range, boost::is_any_of("-"));
|
|
|
|
if (temp_params_list.size() == 1) {
|
|
Maybe<IPAddr> maybe_ip = IPAddr::createIPAddr(temp_params_list[0]);
|
|
if (!maybe_ip.ok()) return genError("Could not create IP address, " + maybe_ip.getErr());
|
|
IpAddress addr = move(ConvertToIpAddress(maybe_ip.unpackMove()));
|
|
|
|
return move(IPRange{.start = addr, .end = addr});
|
|
}
|
|
|
|
if (temp_params_list.size() == 2) {
|
|
Maybe<IPAddr> maybe_ip_min = IPAddr::createIPAddr(temp_params_list[0]);
|
|
Maybe<IPAddr> maybe_ip_max = IPAddr::createIPAddr(temp_params_list[1]);
|
|
if (!maybe_ip_min.ok()) return genError("Could not create IP address, " + maybe_ip_min.getErr());
|
|
if (!maybe_ip_max.ok()) return genError("Could not create IP address, " + maybe_ip_max.getErr());
|
|
|
|
IPAddr min_addr = maybe_ip_min.unpackMove();
|
|
IPAddr max_addr = maybe_ip_max.unpackMove();
|
|
if (min_addr > max_addr) return genError("Could not create ip range - start greater then end");
|
|
|
|
IpAddress addr_min = move(ConvertToIpAddress(move(min_addr)));
|
|
IpAddress addr_max = move(ConvertToIpAddress(move(max_addr)));
|
|
if (addr_max.ip_type != addr_min.ip_type) return genError("Range IP's type does not match");
|
|
|
|
return move(IPRange{.start = move(addr_min), .end = move(addr_max)});
|
|
}
|
|
|
|
return genError("Illegal range received: " + range);
|
|
}
|
|
|
|
Maybe<vector<IPRange>>
|
|
parseIpRanges(const vector<string> &str_ip_ranges)
|
|
{
|
|
vector<IPRange> ip_ranges;
|
|
for (const string &range : str_ip_ranges) {
|
|
Maybe<IPRange> ip_range = createRangeFromStr(range);
|
|
if (!ip_range.ok()) {
|
|
return genError("Failed to parse gradual deployment IP range: " + ip_range.getErr());
|
|
}
|
|
|
|
ip_ranges.push_back(ip_range.unpackMove());
|
|
}
|
|
return move(ip_ranges);
|
|
}
|
|
|
|
Maybe<string>
|
|
convertIpRangeToStr(const IPRange &range)
|
|
{
|
|
if (range.start.ip_type != IP_VERSION_4 && range.start.ip_type != IP_VERSION_6) {
|
|
return genError("Unknown IP type received: " + range.start.ip_type);
|
|
}
|
|
|
|
size_t len;
|
|
int type;
|
|
const void *in_addr_min;
|
|
const void *in_addr_max;
|
|
|
|
if (range.start.ip_type == IP_VERSION_4) {
|
|
len = INET_ADDRSTRLEN;
|
|
type = AF_INET;
|
|
in_addr_min = &range.start.ip.ipv4;
|
|
in_addr_max = &range.end.ip.ipv4;
|
|
} else {
|
|
len = INET6_ADDRSTRLEN;
|
|
type = AF_INET6;
|
|
in_addr_min = &range.start.ip.ipv6;
|
|
in_addr_max = &range.end.ip.ipv6;
|
|
}
|
|
|
|
char str_min[len];
|
|
inet_ntop(type, in_addr_min, str_min, len);
|
|
char str_max[len];
|
|
inet_ntop(type, in_addr_max, str_max, len);
|
|
|
|
string start(str_min, strnlen(str_min, len));
|
|
string end(str_max, strnlen(str_max, len));
|
|
|
|
return start + "-" + end;
|
|
}
|
|
|
|
unordered_map<size_t, vector<IPRange>> ip_ranges_map;
|
|
};
|
|
|
|
GradualDeployment::GradualDeployment() : Component("GradualDeployment"), pimpl(make_unique<Impl>()) {}
|
|
|
|
GradualDeployment::~GradualDeployment() {}
|
|
|
|
void GradualDeployment::init() { pimpl->init(); }
|