1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
/*
* Copyright (c) 2011-2012 ICM Uniwersytet Warszawski All rights reserved.
* See LICENCE file for licensing information.
*
* Derived from the code copyrighted and licensed as follows:
*
* Copyright (c) Members of the EGEE Collaboration. 2004.
* See http://www.eu-egee.org/partners/ for details on the copyright
* holders.
*
* Licensed 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 eu.emi.security.authn.x509.helpers.proxy;
/**
* Helpers for IP addresses comparison.
* Mostly the code from Tigran's ipmatcher library (GNU license).
*
* @author Tigran Mkrtchyan
* @author K. Benedyczak
*/
public class IPAddressHelper
{
private static final int IPv4_FULL_MASK = 32;
private static final int IPv6_FULL_MASK = 128;
private static final int IPv6_HALF_MASK = 64;
/**
* Tests whether the ipAddress is within the address space defined by
* the ipAddressWithNetmask.
*
* @param ipBytes
* The IP address bytes to compare against the address
* space.
* @param ipAddressWithNetmask
* The 8 (IPv4) or 32 (IPv6) byte array containing in the
* first half the base IP address bytes and in the second
* half the netmask bytes.
* @return true if ip matches subnet.
*/
public static boolean isWithinAddressSpace(byte[] ipBytes, byte[] ipAddressWithNetmask) {
if (!(ipAddressWithNetmask.length == 8 && ipBytes.length == 4)
&& !(ipAddressWithNetmask.length == 32 && ipBytes.length == 16))
{
throw new IllegalArgumentException(
"IP address and IP address-netmask length mismatch, should be either (4 and 8) or (16 and 32), actual lengths were: "
+ ipBytes.length
+ " and "
+ ipAddressWithNetmask.length + ".");
}
if (ipBytes.length == 4) {
int mask = getCidrNetmask(4, ipAddressWithNetmask, 4);
/*
* IPv4 can be represented as a 32 bit ints.
*/
int ipAsInt = getInt(ipBytes, 0);
int netAsInt = getInt(ipAddressWithNetmask, 0);
return (ipAsInt ^ netAsInt) >> (IPv4_FULL_MASK - mask) == 0;
}
/**
* IPv6 can be represented as two 64 bit longs.
*
* We evaluate second long only if bitmask bigger than 64. The
* second longs are created only if needed as it turned to be
* the slowest part.
*/
long ipAsLong0 = getLong(ipBytes, 0);
long netAsLong0 = getLong(ipAddressWithNetmask, 0);
int mask = getCidrNetmask(16, ipAddressWithNetmask, 16);
if (mask > 64) {
long ipAsLong1 = getLong(ipBytes, 8);
long netAsLong1 = getLong(ipAddressWithNetmask, 8);
return (ipAsLong0 == netAsLong0)
& (ipAsLong1 ^ netAsLong1) >> (IPv6_FULL_MASK - mask) == 0;
}
return (ipAsLong0 ^ netAsLong0) >> (IPv6_HALF_MASK - mask) == 0;
}
/**
* Returns the big-endian {@code long} value whose byte representation
* is the 8 bytes of <code>bytes</code> staring <code>offset</code>.
*
* @param bytes
* @param offset
* @return long value
*/
private static long getLong(byte[] bytes, int offset) {
return (bytes[offset] & 0xFFL) << 56 | (bytes[offset + 1] & 0xFFL) << 48
| (bytes[offset + 2] & 0xFFL) << 40
| (bytes[offset + 3] & 0xFFL) << 32
| (bytes[offset + 4] & 0xFFL) << 24
| (bytes[offset + 5] & 0xFFL) << 16
| (bytes[offset + 6] & 0xFFL) << 8 | (bytes[offset + 7] & 0xFFL);
}
/**
* Returns the big-endian {@code int} value whose byte representation is
* the 4 bytes of <code>bytes</code> staring <code>offset</code>.
*
* @param bytes
* @param offset
* @return int value
*/
private static int getInt(byte[] bytes, int offset) {
return (bytes[offset + 0] & 0xFF) << 24 | (bytes[offset + 1] & 0xFF) << 16
| (bytes[offset + 2] & 0xFF) << 8 | (bytes[offset + 3] & 0xFF);
}
private static int getCidrNetmask(int size, byte[] netmask, int offset)
{
int ret = 0;
for (int i=0; i<size; i++)
{
if (netmask[i+offset] != -1) //-1 == 255 unsigned
{
int maskByteReversed = (~(netmask[i+offset]))&0xff;
int bitPfx = Integer.numberOfLeadingZeros(maskByteReversed)-24;
return ret+bitPfx;
} else
ret += 8;
}
return ret;
}
}
|