aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/ipreg/range.cpp
diff options
context:
space:
mode:
authorvvvv <vvvv@ydb.tech>2023-07-31 18:21:04 +0300
committervvvv <vvvv@ydb.tech>2023-07-31 18:21:04 +0300
commitdec41c40e51aa407edef81a3c566a5a15780fc49 (patch)
tree4f197b596b32f35eca368121f0dff913419da9af /library/cpp/ipreg/range.cpp
parent3ca8b54c96e09eb2b65be7f09675623438d559c7 (diff)
downloadydb-dec41c40e51aa407edef81a3c566a5a15780fc49.tar.gz
YQL-16239 Move purecalc to public
Diffstat (limited to 'library/cpp/ipreg/range.cpp')
-rw-r--r--library/cpp/ipreg/range.cpp198
1 files changed, 198 insertions, 0 deletions
diff --git a/library/cpp/ipreg/range.cpp b/library/cpp/ipreg/range.cpp
new file mode 100644
index 00000000000..1b900224826
--- /dev/null
+++ b/library/cpp/ipreg/range.cpp
@@ -0,0 +1,198 @@
+#include "range.h"
+
+#include "util_helpers.h"
+
+#include <library/cpp/int128/int128.h>
+#include <util/generic/maybe.h>
+#include <util/string/split.h>
+#include <util/string/vector.h>
+
+#include <stdexcept>
+
+namespace NIPREG {
+
+namespace {
+ EAddressFormat CurrentFormat = EAddressFormat::SHORT_IPV6;
+
+ void throwExceptionWithFormat(const TString& line) {
+ throw yexception() << "wanted format: ${ip-begin}-${ip-end}[\t${data}]; $input := '" << line << "'";
+ }
+
+ void throwIfReverseOrder(TAddress first, TAddress last) {
+ if (first > last) {
+ const TString err_msg = "reverse order of addresses (first / last) => " + first.AsIPv6() + " / " + last.AsIPv6();
+ throw std::runtime_error(err_msg.data());
+ }
+ }
+} // anon-ns
+
+TRange::TRange(TAddress first, TAddress last, const TString& data)
+ : First(first)
+ , Last(last)
+ , Data(data)
+{
+ throwIfReverseOrder(First, Last);
+}
+
+TRange::TRange(const TNetwork& net, const TString& data)
+ : TRange(net.begin, net.end, data)
+{
+}
+
+ui128 TRange::GetAddrsQty() const {
+ return TAddress::Distance(First, Last) + 1;
+}
+
+TRange TRange::BuildRange(const TString& line, bool isEmptyData, const TString& dataDelim) {
+ const TVector<TString> parts = StringSplitter(line).SplitBySet(dataDelim.data()).SkipEmpty();
+ if (parts.empty()) {
+ throwExceptionWithFormat(line);
+ }
+
+ if (TString::npos != parts[0].find('/')) {
+ const auto data = (2 == parts.size()) ? parts[1] : "";
+ return TRange(TNetwork(parts[0]), data);
+ }
+
+ const TVector<TString> range_parts = StringSplitter(parts[0]).SplitBySet(" -\t").SkipEmpty();
+ if (2 != range_parts.size() || range_parts[0].empty() || range_parts[1].empty()) {
+ throwExceptionWithFormat(line);
+ }
+
+ if (!isEmptyData && (2 != parts.size() || parts[1].empty())) {
+ throwExceptionWithFormat(line);
+ }
+
+ const auto& data = (2 == parts.size()) ? parts[1] : "";
+ return TRange(TAddress::ParseAny(range_parts[0]), TAddress::ParseAny(range_parts[1]), data);
+}
+
+bool TRange::Contains(const TRange& range) const {
+ return First <= range.First && range.Last <= Last;
+}
+
+bool TRange::Contains(const TAddress& ip) const {
+ return First <= ip && ip <= Last;
+}
+
+void SetIpFullOutFormat() {
+ CurrentFormat = EAddressFormat::IPV6;
+}
+
+void SetIpShortOutFormat() {
+ CurrentFormat = EAddressFormat::SHORT_IPV6;
+}
+
+void TRange::DumpTo(IOutputStream& output, bool withData, EAddressFormat format) const {
+ output << First.Format(format) << '-' << Last.Format(format);
+ if (withData) {
+ output << '\t' << Data;
+ }
+}
+
+bool TRange::IsIpv6Only() const {
+ return 6 == First.GetType() && 6 == Last.GetType();
+}
+
+bool TRange::IsIpv4Only() const {
+ return 4 == First.GetType() && 4 == Last.GetType();
+}
+
+bool TRange::IsRangeInSingleNet64() const {
+ return First.GetHigh64() == Last.GetHigh64();
+}
+
+TRange TRange::BuildRangeByFirst(const TRange& range, int prefix) {
+ Y_UNUSED(prefix);
+ return TRange(TAddress::MakeNet64Prefix(range.First),
+ TAddress::MakeNet64Broadcast(range.IsRangeInSingleNet64() ? range.Last : range.Last.GetPrevNet64()) ,
+ range.Data
+ );
+}
+
+TRange TRange::BuildRangeByLast(const TRange& range, int prefix) {
+ Y_UNUSED(prefix);
+ const auto prevLast = TAddress::MakeNet64Broadcast(range.Last.GetPrevNet64());
+ return TRange(range.First, prevLast, range.Data);
+// const auto prevLast = TAddress::MakeNet64Broadcast(range.Last);
+// return TRange(TAddress::MakeNet64Prefix(range.First), prevLast, range.Data);
+}
+
+TVector<TRange> SplitRangeNets(const TRange& origRange, bool addOrigSize, int maskLen) {
+ Y_UNUSED(maskLen);
+
+ static const auto firstCheckedIpv6Prefix = TAddress::ParseAny("2000::");
+
+ const auto& CalcNetSize = [&](const TRange& range) {
+ static const auto MAX_FOR_DIGITS_ANSWER = ui128{1 << 30};
+ const auto netSize = range.GetAddrsQty();
+ return (netSize < MAX_FOR_DIGITS_ANSWER) ? ToString(netSize) : "huge";
+ };
+
+ const auto& AddSizeField = [&](TRange& changedRange, const TRange& origAddrRange) {
+ if (addOrigSize) {
+ changedRange.Data = AddJsonAttrs({"orig_net_size"}, changedRange.Data, TMaybe<TString>(CalcNetSize(origAddrRange)));
+ }
+ };
+
+ if (origRange.Last <= firstCheckedIpv6Prefix) {
+ return {origRange};
+ }
+
+ if (origRange.IsRangeInSingleNet64()) {
+ TRange theOne{
+ TAddress::MakeNet64Prefix(origRange.First),
+ TAddress::MakeNet64Broadcast(origRange.Last),
+ origRange.Data
+ };
+ AddSizeField(theOne, origRange);
+ return {theOne};
+ }
+
+ TRange range{origRange};
+ TVector<TRange> result; {
+ // 1st
+ TRange byFirst{TAddress::MakeNet64Prefix(range.First),TAddress::MakeNet64Broadcast(range.First), range.Data};
+ AddSizeField(byFirst, {range.First, byFirst.Last, ""});
+ result.push_back(byFirst);
+
+ // maybe 2nd
+ range.First = byFirst.Last.Next();
+ if (!range.IsRangeInSingleNet64()) {
+ const TAddress lastPrefix = TAddress::MakeNet64Prefix(range.Last);
+
+ TRange inTheMiddle{TAddress::MakeNet64Prefix(range.First), lastPrefix.Prev(), range.Data};
+ AddSizeField(inTheMiddle, inTheMiddle);
+ result.push_back(inTheMiddle);
+
+ range.First = lastPrefix;
+ }
+
+ // the last
+ TRange byLast{range.First, TAddress::MakeNet64Broadcast(range.Last), range.Data};
+ AddSizeField(byLast, {byLast.First, range.Last, ""});
+ result.push_back(byLast);
+ }
+ return result;
+}
+
+bool operator==(const TRange& lhs, const TRange& rhs) {
+ return lhs.First == rhs.First && lhs.Last == rhs.Last;
+}
+
+} // ns IPREG
+
+IInputStream& operator>>(IInputStream& input, NIPREG::TRange& range) {
+ TString line;
+ if (!input.ReadLine(line)) {
+ throw std::runtime_error("unable to load data from stream");
+ }
+ range = NIPREG::TRange::BuildRange(line);
+ return input;
+}
+
+IOutputStream& operator<<(IOutputStream& output, const NIPREG::TRange& range) {
+ range.DumpTo(output, true, NIPREG::CurrentFormat);
+ output << "\n";
+ return output;
+}