File: IPAddressHelper.java

package info (click to toggle)
canl-java 2.8.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 11,792 kB
  • sloc: java: 23,306; xml: 465; sh: 396; makefile: 29
file content (141 lines) | stat: -rw-r--r-- 4,627 bytes parent folder | download | duplicates (6)
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;
	}
}