ipmath_ut.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. #include "ipmath.h"
  2. #include "range_set.h"
  3. #include <library/cpp/testing/unittest/registar.h>
  4. #include <library/cpp/testing/gmock_in_unittest/gmock.h>
  5. #include <library/cpp/ipv6_address/ipv6_address.h>
  6. using namespace testing;
  7. static constexpr auto MIN_IPV6_ADDR = "::";
  8. static constexpr auto MAX_IPV6_ADDR = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff";
  9. std::ostream& operator<<(std::ostream& os, const TIpAddressRange& r) {
  10. auto s = r.ToRangeString();
  11. os.write(s.data(), s.size());
  12. return os;
  13. }
  14. std::ostream& operator<<(std::ostream& os, const TIpRangeSet& rangeSet) {
  15. os << "{\n";
  16. for (auto&& r : rangeSet) {
  17. os << r << '\n';
  18. }
  19. os << "}\n";
  20. return os;
  21. }
  22. class TIpRangeTests: public TTestBase {
  23. public:
  24. UNIT_TEST_SUITE(TIpRangeTests);
  25. UNIT_TEST(IpRangeFromIpv4);
  26. UNIT_TEST(IpRangeFromIpv6);
  27. UNIT_TEST(FullIpRange);
  28. UNIT_TEST(IpRangeFromCidr);
  29. UNIT_TEST(IpRangeFromCompact);
  30. UNIT_TEST(IpRangeFromIpv4Builder);
  31. UNIT_TEST(IpRangeFromInvalidIpv4);
  32. UNIT_TEST(IpRangeFromInvalidIpv6);
  33. UNIT_TEST(RangeFromSingleAddress);
  34. UNIT_TEST(RangeFromRangeString);
  35. UNIT_TEST(ManualIteration);
  36. UNIT_TEST(RangeRelations);
  37. UNIT_TEST(RangeUnion);
  38. UNIT_TEST_SUITE_END();
  39. void RangeFromSingleAddress() {
  40. for (auto addrStr : {"192.168.0.1", "::2"}) {
  41. auto range = TIpAddressRange::From(addrStr).Build();
  42. ASSERT_THAT(range.Size(), Eq(1));
  43. ASSERT_TRUE(range.IsSingle());
  44. auto range2 = TIpAddressRange{addrStr, addrStr};
  45. ASSERT_THAT(range2, Eq(range));
  46. TVector<ui128> result;
  47. range.ForEach([&result] (TIpv6Address addr) {
  48. result.push_back(addr);
  49. });
  50. bool ok{};
  51. ASSERT_THAT(result, ElementsAre(TIpv6Address::FromString(addrStr, ok)));
  52. }
  53. }
  54. void IpRangeFromIpv4() {
  55. bool ok{};
  56. auto s = TIpv6Address::FromString("192.168.0.0", ok);
  57. ASSERT_TRUE(ok);
  58. auto e = TIpv6Address::FromString("192.168.0.255", ok);
  59. ASSERT_TRUE(ok);
  60. TIpAddressRange range{s, e};
  61. ASSERT_THAT(range.Size(), Eq(256));
  62. ASSERT_THAT(range.Type(), Eq(TIpAddressRange::TIpType::Ipv4));
  63. TIpAddressRange range2{"192.168.0.0", "192.168.0.255"};
  64. ASSERT_THAT(range2.Size(), Eq(256));
  65. ASSERT_THAT(range2, Eq(range));
  66. }
  67. void IpRangeFromIpv6() {
  68. bool ok{};
  69. auto s = TIpv6Address::FromString("ffce:abcd::", ok);
  70. ASSERT_TRUE(ok);
  71. auto e = TIpv6Address::FromString("ffce:abcd::00ff", ok);
  72. ASSERT_TRUE(ok);
  73. TIpAddressRange range{s, e};
  74. ASSERT_THAT(range.Size(), Eq(256));
  75. TIpAddressRange range2{"ffce:abcd::", "ffce:abcd::00ff"};
  76. ASSERT_THAT(range2.Size(), Eq(256));
  77. ASSERT_THAT(range.Type(), Eq(TIpAddressRange::TIpType::Ipv6));
  78. ASSERT_THAT(range2, Eq(range));
  79. }
  80. void FullIpRange() {
  81. auto check = [] (auto start, auto end, ui128 expectedSize) {
  82. auto range = TIpAddressRange::From(start).To(end).Build();
  83. ASSERT_THAT(range.Size(), Eq(expectedSize));
  84. };
  85. check("0.0.0.0", "255.255.255.255", ui128(Max<ui32>()) + 1);
  86. // XXX
  87. // check(MIN_IPV6_ADDR, MAX_IPV6_ADDR, ui128(Max<ui128>() + 1));
  88. }
  89. void IpRangeFromCidr() {
  90. auto range = TIpAddressRange::FromCidrString("10.0.0.0/30");
  91. ASSERT_THAT(range.Size(), Eq(4));
  92. TVector<TIpv6Address> result;
  93. Copy(range.begin(), range.end(), std::back_inserter(result));
  94. bool ok;
  95. TVector<TIpv6Address> expected {
  96. TIpv6Address::FromString("10.0.0.0", ok),
  97. TIpv6Address::FromString("10.0.0.1", ok),
  98. TIpv6Address::FromString("10.0.0.2", ok),
  99. TIpv6Address::FromString("10.0.0.3", ok),
  100. };
  101. ASSERT_THAT(result, ElementsAreArray(expected));
  102. // single host
  103. ASSERT_THAT(TIpAddressRange::FromCidrString("ffce:abcd::/128"), Eq(TIpAddressRange::From("ffce:abcd::").Build()));
  104. ASSERT_THAT(TIpAddressRange::FromCidrString("192.168.0.1/32"), Eq(TIpAddressRange::From("192.168.0.1").Build()));
  105. // full range
  106. ASSERT_THAT(TIpAddressRange::FromCidrString("::/0"), Eq(TIpAddressRange::From(MIN_IPV6_ADDR).To(MAX_IPV6_ADDR).Build()));
  107. ASSERT_THAT(TIpAddressRange::FromCidrString("0.0.0.0/0"), Eq(TIpAddressRange::From("0.0.0.0").To("255.255.255.255").Build()));
  108. // illformed
  109. ASSERT_THROW(TIpAddressRange::FromCidrString("::/"), TInvalidIpRangeException);
  110. ASSERT_THROW(TIpAddressRange::FromCidrString("::"), TInvalidIpRangeException);
  111. ASSERT_THROW(TIpAddressRange::FromCidrString("/::"), TInvalidIpRangeException);
  112. ASSERT_THROW(TIpAddressRange::FromCidrString("::/150"), TInvalidIpRangeException);
  113. }
  114. void IpRangeFromCompact() {
  115. // FromCidrString disallows node addresses
  116. EXPECT_THROW(TIpAddressRange::FromCidrString("10.10.36.12/12"), TInvalidIpRangeException);
  117. // FromCompactString allows to use node address instead of network address (suffix of zeroes is not required)
  118. ASSERT_THAT(TIpAddressRange::FromCompactString("10.10.36.12/12"), Eq(TIpAddressRange::FromCidrString("10.0.0.0/12")));
  119. ASSERT_THAT(TIpAddressRange::FromCompactString("abcd:ef01:2345::/24"), Eq(TIpAddressRange::FromCidrString("abcd:ef00::/24")));
  120. }
  121. void RangeFromRangeString() {
  122. {
  123. auto range = TIpAddressRange::FromRangeString("10.0.0.0-10.0.0.3");
  124. TVector<TIpv6Address> result;
  125. Copy(range.begin(), range.end(), std::back_inserter(result));
  126. bool ok;
  127. TVector<TIpv6Address> expected {
  128. TIpv6Address::FromString("10.0.0.0", ok),
  129. TIpv6Address::FromString("10.0.0.1", ok),
  130. TIpv6Address::FromString("10.0.0.2", ok),
  131. TIpv6Address::FromString("10.0.0.3", ok),
  132. };
  133. ASSERT_THAT(result, ElementsAreArray(expected));
  134. }
  135. {
  136. auto range = TIpAddressRange::FromRangeString("10.0.0.0-10.0.0.3");
  137. TVector<TIpv6Address> result;
  138. Copy(range.begin(), range.end(), std::back_inserter(result));
  139. bool ok;
  140. TVector<TIpv6Address> expected {
  141. TIpv6Address::FromString("10.0.0.0", ok),
  142. TIpv6Address::FromString("10.0.0.1", ok),
  143. TIpv6Address::FromString("10.0.0.2", ok),
  144. TIpv6Address::FromString("10.0.0.3", ok),
  145. };
  146. ASSERT_THAT(result, ElementsAreArray(expected));
  147. }
  148. }
  149. void IpRangeFromIpv4Builder() {
  150. auto range = TIpAddressRange::From("192.168.0.0")
  151. .To("192.168.0.255")
  152. .Build();
  153. ASSERT_THAT(range.Size(), Eq(256));
  154. }
  155. void IpRangeFromIpv4BuilderFromTIpv6Address() {
  156. const auto s = TIpv6Address::FromString("192.168.0.0");
  157. const auto e = TIpv6Address::FromString("192.168.0.255");
  158. auto range = TIpAddressRange::From(s).To(e).Build();
  159. ASSERT_THAT(range.Size(), Eq(256));
  160. }
  161. void IpRangeFromInvalidIpv4() {
  162. auto build = [] (auto from, auto to) {
  163. return TIpAddressRange::From(from).To(to).Build();
  164. };
  165. ASSERT_THROW(build("192.168.0.255", "192.168.0.0"), yexception);
  166. ASSERT_THROW(build("192.168.0.0", "192.168.0.300"), yexception);
  167. ASSERT_THROW(build("192.168.0.300", "192.168.0.330"), yexception);
  168. ASSERT_THROW(build("192.168.0.0", "::1"), yexception);
  169. ASSERT_THROW(build(TIpv6Address{}, TIpv6Address{}), yexception);
  170. }
  171. void IpRangeFromInvalidIpv6() {
  172. auto build = [] (auto from, auto to) {
  173. return TIpAddressRange::From(from).To(to).Build();
  174. };
  175. ASSERT_THROW(build("ffce:abcd::00ff", "ffce:abcd::"), yexception);
  176. ASSERT_THROW(build("ffce:abcd::", "ffce:abcd::fffff"), yexception);
  177. ASSERT_THROW(build("ffce:abcd::10000", "ffce:abcd::ffff"), yexception);
  178. ASSERT_THROW(build("ffce:abcd::", TIpv6Address{}), yexception);
  179. auto ctor = [] (auto s, auto e) {
  180. return TIpAddressRange{s, e};
  181. };
  182. ASSERT_THROW(ctor(TIpv6Address{}, TIpv6Address{}), yexception);
  183. ASSERT_THROW(ctor("", ""), yexception);
  184. }
  185. void ManualIteration() {
  186. {
  187. TIpAddressRange range{"::", "::"};
  188. auto it = range.Begin();
  189. ++it;
  190. bool ok;
  191. ASSERT_THAT(*it, Eq(TIpv6Address::FromString("::1", ok)));
  192. for (auto i = 0; i < 254; ++i, ++it) {
  193. }
  194. ASSERT_THAT(*it, Eq(TIpv6Address::FromString("::ff", ok)));
  195. }
  196. {
  197. TIpAddressRange range{"0.0.0.0", "0.0.0.0"};
  198. auto it = range.Begin();
  199. ++it;
  200. bool ok;
  201. ASSERT_THAT(*it, Eq(TIpv6Address::FromString("0.0.0.1", ok)));
  202. for (auto i = 0; i < 254; ++i, ++it) {
  203. }
  204. ASSERT_THAT(*it, Eq(TIpv6Address::FromString("0.0.0.255", ok)));
  205. }
  206. }
  207. void RangeRelations() {
  208. {
  209. auto range = TIpAddressRange::From(MIN_IPV6_ADDR)
  210. .To(MAX_IPV6_ADDR)
  211. .Build();
  212. ASSERT_TRUE(range.Overlaps(range));
  213. ASSERT_TRUE(range.Contains(range));
  214. // XXX
  215. //ASSERT_FALSE(range.IsConsecutive(range));
  216. }
  217. {
  218. auto range = TIpAddressRange::From("0.0.0.1").To("0.0.0.4").Build();
  219. auto range0 = TIpAddressRange::From("0.0.0.0").Build();
  220. auto range1 = TIpAddressRange::From("0.0.0.1").Build();
  221. auto range2 = TIpAddressRange::From("0.0.0.5").Build();
  222. auto range4 = TIpAddressRange::From("0.0.0.4").Build();
  223. ASSERT_FALSE(range.Overlaps(range0));
  224. ASSERT_TRUE(range.IsConsecutive(range0));
  225. ASSERT_FALSE(range.Contains(range0));
  226. ASSERT_TRUE(range.Overlaps(range1));
  227. ASSERT_FALSE(range.IsConsecutive(range1));
  228. ASSERT_TRUE(range.Contains(range1));
  229. ASSERT_TRUE(range.Overlaps(range4));
  230. ASSERT_FALSE(range.IsConsecutive(range4));
  231. ASSERT_TRUE(range.Contains(range4));
  232. }
  233. {
  234. auto range = TIpAddressRange::From("0.0.0.1").To("0.0.0.4").Build();
  235. auto range2 = TIpAddressRange::From("0.0.0.0").To("0.0.0.2").Build();
  236. ASSERT_TRUE(range.Overlaps(range2));
  237. ASSERT_FALSE(range.IsConsecutive(range2));
  238. ASSERT_FALSE(range.Contains(range2));
  239. bool ok;
  240. ASSERT_TRUE(range.Contains(TIpv6Address::FromString("0.0.0.1", ok)));
  241. ASSERT_TRUE(range.Contains(TIpv6Address::FromString("0.0.0.2", ok)));
  242. ASSERT_FALSE(range.Contains(TIpv6Address::FromString("0.0.0.5", ok)));
  243. }
  244. }
  245. void RangeUnion() {
  246. {
  247. auto range = TIpAddressRange::From(MIN_IPV6_ADDR)
  248. .To(MAX_IPV6_ADDR)
  249. .Build();
  250. ASSERT_THAT(range.Union(range), Eq(range));
  251. ASSERT_THAT(range.Union(TIpAddressRange::From("::")), range);
  252. ASSERT_THAT(range.Union(TIpAddressRange::From("::1")), range);
  253. ASSERT_THROW(range.Union(TIpAddressRange::From("0.0.0.0")), yexception);
  254. }
  255. {
  256. auto expected = TIpAddressRange::From("0.0.0.1").To("0.0.0.10").Build();
  257. auto range = TIpAddressRange{"0.0.0.1", "0.0.0.3"}.Union({"0.0.0.4", "0.0.0.10"});
  258. ASSERT_THAT(range, Eq(expected));
  259. auto range2 = TIpAddressRange{"0.0.0.1", "0.0.0.3"}.Union({"0.0.0.2", "0.0.0.10"});
  260. ASSERT_THAT(range2, Eq(expected));
  261. auto range3 = TIpAddressRange{"0.0.0.2", "0.0.0.3"}.Union({"0.0.0.1", "0.0.0.10"});
  262. ASSERT_THAT(range2, Eq(expected));
  263. auto range4 = TIpAddressRange{"0.0.0.1", "0.0.0.10"}.Union({"0.0.0.2", "0.0.0.3"});
  264. ASSERT_THAT(range2, Eq(expected));
  265. ASSERT_THROW(range.Union(TIpAddressRange::From("10.0.0.0")), yexception);
  266. }
  267. }
  268. };
  269. class TRangeSetTests: public TTestBase {
  270. public:
  271. UNIT_TEST_SUITE(TRangeSetTests);
  272. UNIT_TEST(AddDisjoint);
  273. UNIT_TEST(AddOverlapping);
  274. UNIT_TEST(AddConsecutive);
  275. UNIT_TEST(DisallowsMixingTypes);
  276. UNIT_TEST(MembershipTest);
  277. UNIT_TEST_SUITE_END();
  278. void AddDisjoint() {
  279. TIpRangeSet set;
  280. TVector<TIpAddressRange> expected {
  281. TIpAddressRange::From("0.0.0.0").To("0.0.0.2").Build(),
  282. TIpAddressRange::From("0.0.0.4").To("255.255.255.255").Build(),
  283. };
  284. for (auto&& r : expected) {
  285. set.Add(r);
  286. }
  287. ASSERT_THAT(set, ElementsAreArray(expected));
  288. }
  289. void TestAdding(const TVector<TIpAddressRange>& toInsert, const TVector<TIpAddressRange>& expected) {
  290. TIpRangeSet set;
  291. {
  292. set.Add(toInsert);
  293. ASSERT_THAT(set, ElementsAreArray(expected));
  294. }
  295. {
  296. for (auto it = toInsert.rbegin(); it != toInsert.rend(); ++it) {
  297. set.Add(*it);
  298. }
  299. ASSERT_THAT(set, ElementsAreArray(expected));
  300. }
  301. }
  302. void AddOverlapping() {
  303. {
  304. TVector<TIpAddressRange> toInsert {
  305. TIpAddressRange::From("0.0.0.0").To("0.0.0.2").Build(),
  306. TIpAddressRange::From("0.0.0.2").To("0.0.0.4").Build(),
  307. TIpAddressRange::From("0.0.0.4").To("255.255.255.255").Build(),
  308. };
  309. TVector<TIpAddressRange> expected {
  310. TIpAddressRange::From("0.0.0.0").To("255.255.255.255").Build(),
  311. };
  312. TestAdding(toInsert, expected);
  313. }
  314. {
  315. TVector<TIpAddressRange> toInsert {
  316. TIpAddressRange::From("0.0.0.0").To("0.0.0.5").Build(),
  317. TIpAddressRange::From("0.0.0.8").To("0.0.0.10").Build(),
  318. TIpAddressRange::From("0.0.0.7").To("0.0.0.12").Build(),
  319. };
  320. TVector<TIpAddressRange> expected {
  321. TIpAddressRange::From("0.0.0.0").To("0.0.0.5").Build(),
  322. TIpAddressRange::From("0.0.0.7").To("0.0.0.12").Build(),
  323. };
  324. TestAdding(toInsert, expected);
  325. }
  326. {
  327. TVector<TIpAddressRange> toInsert {
  328. TIpAddressRange::From("0.0.0.0").To("0.0.0.5").Build(),
  329. TIpAddressRange::From("0.0.0.7").To("0.0.0.12").Build(),
  330. TIpAddressRange::From("0.0.0.8").To("0.0.0.10").Build(),
  331. };
  332. TVector<TIpAddressRange> expected {
  333. TIpAddressRange::From("0.0.0.0").To("0.0.0.5").Build(),
  334. TIpAddressRange::From("0.0.0.7").To("0.0.0.12").Build(),
  335. };
  336. TestAdding(toInsert, expected);
  337. }
  338. {
  339. TVector<TIpAddressRange> toInsert {
  340. TIpAddressRange::From("0.0.0.0").To("0.0.0.5").Build(),
  341. TIpAddressRange::From("0.0.0.3").To("0.0.0.10").Build(),
  342. };
  343. TVector<TIpAddressRange> expected {
  344. TIpAddressRange::From("0.0.0.0").To("0.0.0.10").Build(),
  345. };
  346. TestAdding(toInsert, expected);
  347. }
  348. }
  349. void DisallowsMixingTypes() {
  350. TVector<TIpAddressRange> toInsert {
  351. TIpAddressRange::From("0.0.0.0").To("0.0.0.5").Build(),
  352. TIpAddressRange::From("::1").Build(),
  353. };
  354. TIpRangeSet rangeSet;
  355. ASSERT_THROW([&] { rangeSet.Add(toInsert); }(), yexception);
  356. ASSERT_THROW([&] { rangeSet.Add(toInsert[1]); rangeSet.Add(toInsert[0]); }(), yexception);
  357. }
  358. void AddConsecutive() {
  359. {
  360. TVector<TIpAddressRange> toInsert {
  361. TIpAddressRange::From("0.0.0.0").To("0.0.0.5").Build(),
  362. TIpAddressRange::From("0.0.0.6").To("0.0.0.7").Build(),
  363. TIpAddressRange::From("0.0.0.8").To("0.0.0.10").Build(),
  364. };
  365. TVector<TIpAddressRange> expected {
  366. TIpAddressRange::From("0.0.0.0").To("0.0.0.10").Build(),
  367. };
  368. TestAdding(toInsert, expected);
  369. }
  370. {
  371. TVector<TIpAddressRange> toInsert {
  372. TIpAddressRange::From("0.0.0.0").To("255.255.255.255").Build(),
  373. TIpAddressRange::From("0.0.0.0").To("255.255.255.255").Build(),
  374. };
  375. TVector<TIpAddressRange> expected {
  376. TIpAddressRange::From("0.0.0.0").To("255.255.255.255").Build(),
  377. };
  378. TestAdding(toInsert, expected);
  379. }
  380. }
  381. void MembershipTest() {
  382. TVector<TIpAddressRange> toInsert {
  383. TIpAddressRange::From("0.0.0.0").To("0.0.0.5").Build(),
  384. TIpAddressRange::From("0.0.0.7").To("0.0.0.12").Build(),
  385. TIpAddressRange::From("0.0.0.8").To("0.0.0.10").Build(),
  386. };
  387. TIpRangeSet rangeSet;
  388. rangeSet.Add(toInsert);
  389. TVector<TIpAddressRange> in {
  390. TIpAddressRange::From("0.0.0.0").To("0.0.0.5").Build(),
  391. TIpAddressRange::From("0.0.0.7").To("0.0.0.12").Build(),
  392. };
  393. TVector<TIpAddressRange> notIn {
  394. TIpAddressRange::From("0.0.0.6").Build(),
  395. TIpAddressRange::From("0.0.0.13").To("0.0.0.255").Build(),
  396. // enumerating full range is slow and makes little sense
  397. TIpAddressRange::From("255.255.255.0").To("255.255.255.255").Build(),
  398. };
  399. for (auto&& range : in) {
  400. for (auto&& addr : range) {
  401. ASSERT_TRUE(rangeSet.Contains(addr));
  402. ASSERT_THAT(*rangeSet.Find(addr), Eq(range));
  403. }
  404. }
  405. for (auto&& range : notIn) {
  406. for (auto&& addr : range) {
  407. ASSERT_FALSE(rangeSet.Contains(addr));
  408. ASSERT_THAT(rangeSet.Find(addr), rangeSet.End());
  409. }
  410. }
  411. bool ok{};
  412. ASSERT_THAT(rangeSet.Find(TIpv6Address::FromString("::1", ok)), Eq(rangeSet.End()));
  413. ASSERT_FALSE(rangeSet.Contains(TIpv6Address::FromString("::1", ok)));
  414. }
  415. };
  416. UNIT_TEST_SUITE_REGISTRATION(TIpRangeTests);
  417. UNIT_TEST_SUITE_REGISTRATION(TRangeSetTests);