|
@@ -0,0 +1,192 @@
|
|
|
+/*
|
|
|
+ * Licensed to Elasticsearch under one or more contributor
|
|
|
+ * license agreements. See the NOTICE file distributed with
|
|
|
+ * this work for additional information regarding copyright
|
|
|
+ * ownership. Elasticsearch licenses this file to you under
|
|
|
+ * the Apache License, Version 2.0 (the "License"); you may
|
|
|
+ * not use this file except in compliance with 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.
|
|
|
+ */
|
|
|
+
|
|
|
+package org.elasticsearch.common.network;
|
|
|
+
|
|
|
+import org.elasticsearch.common.collect.Tuple;
|
|
|
+import org.elasticsearch.common.network.Cidrs;
|
|
|
+import org.elasticsearch.search.aggregations.bucket.range.ipv4.IPv4RangeBuilder;
|
|
|
+import org.elasticsearch.test.ESTestCase;
|
|
|
+
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+import static org.hamcrest.Matchers.*;
|
|
|
+
|
|
|
+public class CidrsTests extends ESTestCase {
|
|
|
+ public void testNullCidr() {
|
|
|
+ try {
|
|
|
+ Cidrs.cidrMaskToMinMax(null);
|
|
|
+ fail("expected NullPointerException");
|
|
|
+ } catch (NullPointerException e) {
|
|
|
+ assertThat(e, hasToString(containsString("cidr")));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testSplittingSlash() {
|
|
|
+ List<String> cases = new ArrayList<>();
|
|
|
+ cases.add("1.2.3.4");
|
|
|
+ cases.add("1.2.3.4/32/32");
|
|
|
+ cases.add("1.2.3.4/");
|
|
|
+ cases.add("/");
|
|
|
+ for (String test : cases) {
|
|
|
+ try {
|
|
|
+ Cidrs.cidrMaskToMinMax(test);
|
|
|
+ fail("expected IllegalArgumentException after splitting");
|
|
|
+ } catch (IllegalArgumentException e) {
|
|
|
+ assertThat(e, hasToString(containsString("expected [a.b.c.d, e]")));
|
|
|
+ assertThat(e, hasToString(containsString("splitting on \"/\"")));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testSplittingDot() {
|
|
|
+ List<String> cases = new ArrayList<>();
|
|
|
+ cases.add("1.2.3/32");
|
|
|
+ cases.add("1/32");
|
|
|
+ cases.add("1./32");
|
|
|
+ cases.add("1../32");
|
|
|
+ cases.add("1.../32");
|
|
|
+ cases.add("1.2.3.4.5/32");
|
|
|
+ cases.add("/32");
|
|
|
+ for (String test : cases) {
|
|
|
+ try {
|
|
|
+ Cidrs.cidrMaskToMinMax(test);
|
|
|
+ fail("expected IllegalArgumentException after splitting");
|
|
|
+ } catch (IllegalArgumentException e) {
|
|
|
+ assertThat(e, hasToString(containsString("unable to parse")));
|
|
|
+ assertThat(e, hasToString(containsString("as an IP address literal")));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testValidSpecificCases() {
|
|
|
+ List<Tuple<String, long[]>> cases = new ArrayList<>();
|
|
|
+ cases.add(new Tuple<>("192.168.0.0/24", new long[]{(192L << 24) + (168 << 16), (192L << 24) + (168 << 16) + (1 << 8)}));
|
|
|
+ cases.add(new Tuple<>("192.168.128.0/17", new long[]{(192L << 24) + (168 << 16) + (128 << 8), (192L << 24) + (168 << 16) + (128 << 8) + (1 << 15)}));
|
|
|
+ cases.add(new Tuple<>("128.0.0.0/1", new long[]{128L << 24, (128L << 24) + (1L << 31)})); // edge case
|
|
|
+ cases.add(new Tuple<>("0.0.0.0/0", new long[]{0, 1L << 32})); // edge case
|
|
|
+ cases.add(new Tuple<>("0.0.0.0/1", new long[]{0, 1L << 31})); // edge case
|
|
|
+ cases.add(new Tuple<>(
|
|
|
+ "192.168.1.1/32",
|
|
|
+ new long[]{(192L << 24) + (168L << 16) + (1L << 8) + 1L, (192L << 24) + (168L << 16) + (1L << 8) + 1L + 1})
|
|
|
+ ); // edge case
|
|
|
+ for (Tuple<String, long[]> test : cases) {
|
|
|
+ long[] actual = Cidrs.cidrMaskToMinMax(test.v1());
|
|
|
+ assertArrayEquals(test.v1(), test.v2(), actual);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testInvalidSpecificOctetCases() {
|
|
|
+ List<String> cases = new ArrayList<>();
|
|
|
+ cases.add("256.0.0.0/8"); // first octet out of range
|
|
|
+ cases.add("255.256.0.0/16"); // second octet out of range
|
|
|
+ cases.add("255.255.256.0/24"); // third octet out of range
|
|
|
+ cases.add("255.255.255.256/32"); // fourth octet out of range
|
|
|
+ cases.add("abc.0.0.0/8"); // octet that can not be parsed
|
|
|
+ cases.add("-1.0.0.0/8"); // first octet out of range
|
|
|
+ cases.add("128.-1.0.0/16"); // second octet out of range
|
|
|
+ cases.add("128.128.-1.0/24"); // third octet out of range
|
|
|
+ cases.add("128.128.128.-1/32"); // fourth octet out of range
|
|
|
+
|
|
|
+ for (String test : cases) {
|
|
|
+ try {
|
|
|
+ Cidrs.cidrMaskToMinMax(test);
|
|
|
+ fail("expected invalid address");
|
|
|
+ } catch (IllegalArgumentException e) {
|
|
|
+ assertThat(e, hasToString(containsString("unable to parse")));
|
|
|
+ assertThat(e, hasToString(containsString("as an IP address literal")));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testInvalidSpecificNetworkMaskCases() {
|
|
|
+ List<String> cases = new ArrayList<>();
|
|
|
+ cases.add("128.128.128.128/-1"); // network mask out of range
|
|
|
+ cases.add("128.128.128.128/33"); // network mask out of range
|
|
|
+ cases.add("128.128.128.128/abc"); // network mask that can not be parsed
|
|
|
+
|
|
|
+ for (String test : cases) {
|
|
|
+ try {
|
|
|
+ Cidrs.cidrMaskToMinMax(test);
|
|
|
+ fail("expected invalid network mask");
|
|
|
+ } catch (IllegalArgumentException e) {
|
|
|
+ assertThat(e, hasToString(containsString("network mask")));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testValidCombinations() {
|
|
|
+ for (long i = 0; i < (1 << 16); i++) {
|
|
|
+ for (int mask = 16; mask <= 32; mask++) {
|
|
|
+ String test = Cidrs.octetsToCIDR(Cidrs.longToOctets(i << 16), mask);
|
|
|
+ long[] actual = Cidrs.cidrMaskToMinMax(test);
|
|
|
+ assertNotNull(test, actual);
|
|
|
+ assertEquals(test, 2, actual.length);
|
|
|
+ assertEquals(test, i << 16, actual[0]);
|
|
|
+ assertEquals(test, (i << 16) + (1L << (32 - mask)), actual[1]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testInvalidCombinations() {
|
|
|
+ List<String> cases = new ArrayList<>();
|
|
|
+ cases.add("192.168.0.1/24"); // invalid because fourth octet is not zero
|
|
|
+ cases.add("192.168.1.0/16"); // invalid because third octet is not zero
|
|
|
+ cases.add("192.1.0.0/8"); // invalid because second octet is not zero
|
|
|
+ cases.add("128.0.0.0/0"); // invalid because first octet is not zero
|
|
|
+ // create cases that have a bit set outside of the network mask
|
|
|
+ int value = 1;
|
|
|
+ for (int i = 0; i < 31; i++) {
|
|
|
+ cases.add(Cidrs.octetsToCIDR(Cidrs.longToOctets(value), 32 - i - 1));
|
|
|
+ value <<= 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (String test : cases) {
|
|
|
+ try {
|
|
|
+ Cidrs.cidrMaskToMinMax(test);
|
|
|
+ fail("expected invalid combination");
|
|
|
+ } catch (IllegalArgumentException e) {
|
|
|
+ assertThat(test, e, hasToString(containsString("invalid address/network mask combination")));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testRandomValidCombinations() {
|
|
|
+ List<Tuple<String, Integer>> cases = new ArrayList<>();
|
|
|
+ // random number of strings with valid octets and valid network masks
|
|
|
+ for (int i = 0; i < randomIntBetween(1, 1024); i++) {
|
|
|
+ int networkMask = randomIntBetween(0, 32);
|
|
|
+ long mask = (1L << (32 - networkMask)) - 1;
|
|
|
+ long address = randomLongInIPv4Range() & ~mask;
|
|
|
+ cases.add(new Tuple<>(Cidrs.octetsToCIDR(Cidrs.longToOctets(address), networkMask), networkMask));
|
|
|
+ }
|
|
|
+
|
|
|
+ for (Tuple<String, Integer> test : cases) {
|
|
|
+ long[] actual = Cidrs.cidrMaskToMinMax(test.v1());
|
|
|
+ assertNotNull(test.v1(), actual);
|
|
|
+ assertEquals(test.v1(), 2, actual.length);
|
|
|
+ // assert the resulting block has the right size
|
|
|
+ assertEquals(test.v1(), 1L << (32 - test.v2()), actual[1] - actual[0]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private long randomLongInIPv4Range() {
|
|
|
+ return randomLong() & 0x00000000FFFFFFFFL;
|
|
|
+ }
|
|
|
+}
|