org.elasticsearch.common.network.Cidrs Maven / Gradle / Ivy
The newest version!
/*
* 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 java.util.Arrays;
import java.util.Locale;
import java.util.Objects;
public final class Cidrs {
private Cidrs() {
}
/**
* Parses an IPv4 address block in CIDR notation into a pair of
* longs representing the bottom and top of the address block
*
* @param cidr an address block in CIDR notation a.b.c.d/n
* @return array representing the address block
* @throws IllegalArgumentException if the cidr can not be parsed
*/
public static long[] cidrMaskToMinMax(String cidr) {
Objects.requireNonNull(cidr, "cidr");
String[] fields = cidr.split("/");
if (fields.length != 2) {
throw new IllegalArgumentException(
String.format(Locale.ROOT, "invalid IPv4/CIDR; expected [a.b.c.d, e] but was [%s] after splitting on \"/\" in [%s]",
Arrays.toString(fields), cidr)
);
}
// do not try to parse IPv4-mapped IPv6 address
if (fields[0].contains(":")) {
throw new IllegalArgumentException(
String.format(Locale.ROOT, "invalid IPv4/CIDR; expected [a.b.c.d, e] where a, b, c, d are decimal octets " +
"but was [%s] after splitting on \"/\" in [%s]", Arrays.toString(fields), cidr)
);
}
byte[] addressBytes;
try {
addressBytes = InetAddresses.forString(fields[0]).getAddress();
} catch (Exception e) {
throw new IllegalArgumentException(
String.format(Locale.ROOT, "invalid IPv4/CIDR; unable to parse [%s] as an IP address literal", fields[0]), e
);
}
long accumulator =
((addressBytes[0] & 0xFFL) << 24) +
((addressBytes[1] & 0xFFL) << 16) +
((addressBytes[2] & 0xFFL) << 8) +
((addressBytes[3] & 0xFFL));
int networkMask;
try {
networkMask = Integer.parseInt(fields[1]);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(
String.format(Locale.ROOT, "invalid IPv4/CIDR; invalid network mask [%s] in [%s]", fields[1], cidr),
e
);
}
if (networkMask < 0 || networkMask > 32) {
throw new IllegalArgumentException(
String.format(Locale.ROOT, "invalid IPv4/CIDR; invalid network mask [%s], out of range in [%s]", fields[1], cidr)
);
}
long blockSize = 1L << (32 - networkMask);
// validation
if ((accumulator & (blockSize - 1)) != 0) {
throw new IllegalArgumentException(
String.format(
Locale.ROOT,
"invalid IPv4/CIDR; invalid address/network mask combination in [%s]; perhaps [%s] was intended?",
cidr,
octetsToCIDR(longToOctets(accumulator - (accumulator & (blockSize - 1))), networkMask)
)
);
}
return new long[] { accumulator, accumulator + blockSize };
}
static int[] longToOctets(long value) {
assert value >= 0 && value <= (1L << 32) : value;
int[] octets = new int[4];
octets[0] = (int)((value >> 24) & 0xFF);
octets[1] = (int)((value >> 16) & 0xFF);
octets[2] = (int)((value >> 8) & 0xFF);
octets[3] = (int)(value & 0xFF);
return octets;
}
static String octetsToString(int[] octets) {
assert octets != null;
assert octets.length == 4;
return String.format(Locale.ROOT, "%d.%d.%d.%d", octets[0], octets[1], octets[2], octets[3]);
}
static String octetsToCIDR(int[] octets, int networkMask) {
assert octets != null;
assert octets.length == 4;
return octetsToString(octets) + "/" + networkMask;
}
public static String createCIDR(long ipAddress, int networkMask) {
return octetsToCIDR(longToOctets(ipAddress), networkMask);
}
}