0
0
mirror of https://github.com/OpenVPN/openvpn3.git synced 2024-09-20 04:02:15 +02:00
openvpn3/openvpn/addr/addrpair.hpp
Leonard Ossa 3646265d15 Refactor nested namespace to C++17 style
Signed-off-by: Leonard Ossa <leonard.ossa@openvpn.com>
2024-07-03 10:20:11 +00:00

223 lines
6.2 KiB
C++

// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2022 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
#ifndef OPENVPN_ADDR_ADDRPAIR_H
#define OPENVPN_ADDR_ADDRPAIR_H
#include <sstream>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/number.hpp>
#include <openvpn/common/split.hpp>
#include <openvpn/addr/ip.hpp>
namespace openvpn::IP {
// AddrMaskPair is basically an object that combines an IP address (v4 or v6)
// with a netmask or prefix length.
struct AddrMaskPair
{
public:
OPENVPN_EXCEPTION(addr_pair_mask_parse_error);
class StringPair
{
public:
OPENVPN_SIMPLE_EXCEPTION(addr_pair_string_error);
StringPair()
: size_(0)
{
}
explicit StringPair(const std::string &s1)
: size_(1)
{
data[0] = s1;
}
explicit StringPair(const std::string &s1, const std::string &s2)
: size_(2)
{
data[0] = s1;
data[1] = s2;
}
void push_back(const std::string &s)
{
if (size_ < 2)
data[size_++] = s;
else
throw addr_pair_string_error();
}
const std::string &operator[](const size_t i) const
{
if (i >= 2)
throw addr_pair_string_error();
return data[i];
}
std::string &operator[](const size_t i)
{
if (i >= 2)
throw addr_pair_string_error();
return data[i];
}
size_t size() const
{
return size_;
}
std::string render() const
{
switch (size_)
{
case 1:
return data[0];
case 2:
return data[0] + "/" + data[1];
default:
return "";
}
}
private:
std::string data[2];
unsigned int size_;
};
static AddrMaskPair from_string(const std::string &s1, const std::string &s2, const char *title = nullptr)
{
try
{
if (s2.empty())
{
const StringPair pair = Split::by_char<StringPair, NullLex, Split::NullLimit>(s1, '/');
return from_string_impl(pair, title);
}
else
{
const StringPair pair(s1, s2);
return from_string_impl(pair, title);
}
}
catch (const std::exception &e)
{
const StringPair pair(s1, s2);
error(e, pair.render(), title);
}
return AddrMaskPair(); // NOTREACHED
}
static AddrMaskPair from_string(const std::string &s, const char *title = nullptr)
{
try
{
const StringPair pair = Split::by_char<StringPair, NullLex, Split::NullLimit>(s, '/');
return from_string_impl(pair, title);
}
catch (const std::exception &e)
{
error(e, s, title);
}
return AddrMaskPair(); // NOTREACHED
}
static AddrMaskPair from_string(const StringPair &pair, const char *title = nullptr)
{
try
{
return from_string_impl(pair, title);
}
catch (const std::exception &e)
{
error(e, pair.render(), title);
}
return AddrMaskPair(); // NOTREACHED
}
std::string to_string(const bool netmask_form = false) const
{
std::ostringstream os;
if (netmask_form)
os << addr.to_string() << '/' << netmask.to_string();
else
os << addr.to_string() << '/' << netmask.prefix_len();
return os.str();
}
bool is_canonical() const
{
return (addr & netmask) == addr;
}
Addr::Version version() const
{
const Addr::Version v1 = addr.version();
const Addr::Version v2 = netmask.version();
if (v1 == v2)
return v1;
else
return Addr::UNSPEC;
}
Addr addr;
Addr netmask;
private:
static void error(const std::exception &e, const std::string &s, const char *title)
{
if (!title)
title = "";
OPENVPN_THROW(addr_pair_mask_parse_error, "AddrMaskPair parse error '" << title << "': " << s << " : " << e.what());
}
static AddrMaskPair from_string_impl(const StringPair &pair, const char *title = nullptr)
{
AddrMaskPair ret;
if (pair.size() == 1 || pair.size() == 2)
{
ret.addr = Addr::from_string(pair[0], title);
if (pair.size() == 2 && !pair[1].empty())
{
if (is_number(pair[1].c_str()))
ret.netmask = Addr::netmask_from_prefix_len(ret.addr.version(),
parse_number_throw<unsigned int>(pair[1], "prefix length"));
else
ret.netmask = Addr::from_string(pair[1]);
ret.netmask.prefix_len(); // verify that netmask is ok
}
else
ret.netmask = Addr::from_zero_complement(ret.addr.version());
ret.addr.verify_version_consistency(ret.netmask);
}
else
throw addr_pair_mask_parse_error("only one or two address terms allowed");
return ret;
}
};
OPENVPN_OSTREAM(AddrMaskPair, to_string)
} // namespace openvpn::IP
#endif