ipmath_ut.cpp 17 KB

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