blob: 79abbf21a0d789a404eef278eb4cc8f4a9264a2f [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
Jonathan Hartdec62d42014-09-22 15:59:04 -070019package org.onlab.packet;
20
21import java.util.Arrays;
22
Jonathan Hartab63aac2014-10-16 08:52:55 -070023
24
Jonathan Hartdec62d42014-09-22 15:59:04 -070025/**
26 * A class representing an IPv4 address.
27 * <p/>
28 * TODO this class is a clone of IpPrefix and still needs to be modified to
29 * look more like an IpAddress.
30 */
Jonathan Hartab63aac2014-10-16 08:52:55 -070031public final class IpAddress implements Comparable<IpAddress> {
Jonathan Hartdec62d42014-09-22 15:59:04 -070032
33 // TODO a comparator for netmasks? E.g. for sorting by prefix match order.
34
35 //IP Versions
36 public enum Version { INET, INET6 };
37
38 //lengths of address, in bytes
39 public static final int INET_LEN = 4;
40 public static final int INET6_LEN = 16;
41
42 //maximum CIDR value
43 public static final int MAX_INET_MASK = 32;
44 //no mask (no network), e.g. a simple address
45 public static final int DEFAULT_MASK = 0;
46
47 /**
48 * Default value indicating an unspecified address.
49 */
50 static final byte[] ANY = new byte [] {0, 0, 0, 0};
51
52 protected Version version;
53
54 protected byte[] octets;
55 protected int netmask;
56
57 private IpAddress(Version ver, byte[] octets, int netmask) {
58 this.version = ver;
59 this.octets = Arrays.copyOf(octets, INET_LEN);
60 this.netmask = netmask;
61 }
62
63 private IpAddress(Version ver, byte[] octets) {
64 this.version = ver;
65 this.octets = Arrays.copyOf(octets, INET_LEN);
66 this.netmask = DEFAULT_MASK;
67 }
68
69 /**
70 * Converts a byte array into an IP address.
71 *
72 * @param address a byte array
73 * @return an IP address
74 */
75 public static IpAddress valueOf(byte [] address) {
76 return new IpAddress(Version.INET, address);
77 }
78
79 /**
80 * Converts a byte array into an IP address.
81 *
82 * @param address a byte array
83 * @param netmask the CIDR value subnet mask
84 * @return an IP address
85 */
86 public static IpAddress valueOf(byte [] address, int netmask) {
87 return new IpAddress(Version.INET, address, netmask);
88 }
89
90 /**
91 * Helper to convert an integer into a byte array.
92 *
93 * @param address the integer to convert
94 * @return a byte array
95 */
96 private static byte [] bytes(int address) {
97 byte [] bytes = new byte [INET_LEN];
98 for (int i = 0; i < INET_LEN; i++) {
99 bytes[i] = (byte) ((address >> (INET_LEN - (i + 1)) * 8) & 0xff);
100 }
101
102 return bytes;
103 }
104
105 /**
106 * Converts an integer into an IPv4 address.
107 *
108 * @param address an integer representing an IP value
109 * @return an IP address
110 */
111 public static IpAddress valueOf(int address) {
112 return new IpAddress(Version.INET, bytes(address));
113 }
114
115 /**
116 * Converts an integer into an IPv4 address.
117 *
118 * @param address an integer representing an IP value
119 * @param netmask the CIDR value subnet mask
120 * @return an IP address
121 */
122 public static IpAddress valueOf(int address, int netmask) {
123 return new IpAddress(Version.INET, bytes(address), netmask);
124 }
125
126 /**
127 * Converts a dotted-decimal string (x.x.x.x) into an IPv4 address. The
128 * string can also be in CIDR (slash) notation. If the netmask is omitted,
129 * it will be set to DEFAULT_MASK (0).
130 *
131 * @param address a IP address in string form, e.g. "10.0.0.1", "10.0.0.1/24"
132 * @return an IP address
133 */
134 public static IpAddress valueOf(String address) {
135
136 final String [] parts = address.split("\\/");
137 if (parts.length > 2) {
138 throw new IllegalArgumentException("Malformed IP address string; "
139 + "Address must take form \"x.x.x.x\" or \"x.x.x.x/y\"");
140 }
141
142 int mask = DEFAULT_MASK;
143 if (parts.length == 2) {
Yuta HIGUCHI7f3df232014-10-15 23:38:24 -0700144 mask = Integer.parseInt(parts[1]);
Jonathan Hartdec62d42014-09-22 15:59:04 -0700145 if (mask > MAX_INET_MASK) {
146 throw new IllegalArgumentException(
147 "Value of subnet mask cannot exceed "
148 + MAX_INET_MASK);
149 }
150 }
151
152 final String [] net = parts[0].split("\\.");
153 if (net.length != INET_LEN) {
154 throw new IllegalArgumentException("Malformed IP address string; "
155 + "Address must have four decimal values separated by dots (.)");
156 }
157 final byte [] bytes = new byte[INET_LEN];
158 for (int i = 0; i < INET_LEN; i++) {
159 bytes[i] = (byte) Short.parseShort(net[i], 10);
160 }
161 return new IpAddress(Version.INET, bytes, mask);
162 }
163
164 /**
165 * Returns the IP version of this address.
166 *
167 * @return the version
168 */
169 public Version version() {
170 return this.version;
171 }
172
173 /**
174 * Returns the IP address as a byte array.
175 *
176 * @return a byte array
177 */
178 public byte[] toOctets() {
179 return Arrays.copyOf(this.octets, INET_LEN);
180 }
181
182 /**
183 * Returns the IP address prefix length.
184 *
185 * @return prefix length
186 */
187 public int prefixLength() {
188 return netmask;
189 }
190
191 /**
192 * Returns the integral value of this IP address.
193 *
194 * @return the IP address's value as an integer
195 */
196 public int toInt() {
Jonathan Hartdc711bd2014-10-15 11:24:23 -0700197 int val = 0;
198 for (int i = 0; i < octets.length; i++) {
199 val <<= 8;
200 val |= octets[i] & 0xff;
201 }
202 return val;
203 }
204
Jonathan Hartdec62d42014-09-22 15:59:04 -0700205 /**
Jonathan Hart335ef462014-10-16 08:20:46 -0700206 * Converts the IP address to a /32 IP prefix.
207 *
208 * @return the new IP prefix
209 */
210 public IpPrefix toPrefix() {
211 return IpPrefix.valueOf(octets, MAX_INET_MASK);
212 }
213
214 /**
Jonathan Hartdec62d42014-09-22 15:59:04 -0700215 * Helper for computing the mask value from CIDR.
216 *
217 * @return an integer bitmask
218 */
219 private int mask() {
220 int shift = MAX_INET_MASK - this.netmask;
221 return ((Integer.MAX_VALUE >>> (shift - 1)) << shift);
222 }
223
224 /**
225 * Returns the subnet mask in IpAddress form. The netmask value for
226 * the returned IpAddress is 0, as the address itself is a mask.
227 *
228 * @return the subnet mask
229 */
230 public IpAddress netmask() {
231 return new IpAddress(Version.INET, bytes(mask()));
232 }
233
234 /**
235 * Returns the network portion of this address as an IpAddress.
236 * The netmask of the returned IpAddress is the current mask. If this
237 * address doesn't have a mask, this returns an all-0 IpAddress.
238 *
239 * @return the network address or null
240 */
241 public IpAddress network() {
242 if (netmask == DEFAULT_MASK) {
243 return new IpAddress(version, ANY, DEFAULT_MASK);
244 }
245
246 byte [] net = new byte [4];
247 byte [] mask = bytes(mask());
248 for (int i = 0; i < INET_LEN; i++) {
249 net[i] = (byte) (octets[i] & mask[i]);
250 }
251 return new IpAddress(version, net, netmask);
252 }
253
254 /**
255 * Returns the host portion of the IPAddress, as an IPAddress.
256 * The netmask of the returned IpAddress is the current mask. If this
257 * address doesn't have a mask, this returns a copy of the current
258 * address.
259 *
260 * @return the host address
261 */
262 public IpAddress host() {
263 if (netmask == DEFAULT_MASK) {
264 new IpAddress(version, octets, netmask);
265 }
266
267 byte [] host = new byte [INET_LEN];
268 byte [] mask = bytes(mask());
269 for (int i = 0; i < INET_LEN; i++) {
270 host[i] = (byte) (octets[i] & ~mask[i]);
271 }
272 return new IpAddress(version, host, netmask);
273 }
274
275 public boolean isMasked() {
276 return mask() != 0;
277 }
278
279 /**
280 * Determines whether a given address is contained within this IpAddress'
281 * network.
282 *
283 * @param other another IP address that could be contained in this network
284 * @return true if the other IP address is contained in this address'
285 * network, otherwise false
286 */
287 public boolean contains(IpAddress other) {
288 if (this.netmask <= other.netmask) {
289 // Special case where they're both /32 addresses
290 if (this.netmask == MAX_INET_MASK) {
291 return Arrays.equals(octets, other.octets);
292 }
293
294 // Mask the other address with our network mask
295 IpAddress otherMasked =
296 IpAddress.valueOf(other.octets, netmask).network();
297
298 return network().equals(otherMasked);
299 }
300 return false;
301 }
302
303 @Override
Jonathan Hartab63aac2014-10-16 08:52:55 -0700304 public int compareTo(IpAddress o) {
Jonathan Hartbcae7bd2014-10-16 10:24:41 -0700305 Long lv = ((long) this.toInt()) & 0xffffffffL;
306 Long rv = ((long) o.toInt()) & 0xffffffffL;
Jonathan Hartab63aac2014-10-16 08:52:55 -0700307 return lv.compareTo(rv);
308 }
309
310 @Override
Jonathan Hartdec62d42014-09-22 15:59:04 -0700311 public int hashCode() {
312 final int prime = 31;
313 int result = 1;
314 result = prime * result + netmask;
315 result = prime * result + Arrays.hashCode(octets);
316 result = prime * result + ((version == null) ? 0 : version.hashCode());
317 return result;
318 }
319
320 @Override
321 public boolean equals(Object obj) {
322 if (this == obj) {
323 return true;
324 }
325 if (obj == null) {
326 return false;
327 }
328 if (getClass() != obj.getClass()) {
329 return false;
330 }
331 IpAddress other = (IpAddress) obj;
332 if (netmask != other.netmask) {
333 return false;
334 }
335 if (!Arrays.equals(octets, other.octets)) {
336 return false;
337 }
338 if (version != other.version) {
339 return false;
340 }
341 return true;
342 }
343
344 @Override
345 /*
346 * (non-Javadoc)
347 * format is "x.x.x.x" for non-masked (netmask 0) addresses,
348 * and "x.x.x.x/y" for masked addresses.
349 *
350 * @see java.lang.Object#toString()
351 */
352 public String toString() {
353 final StringBuilder builder = new StringBuilder();
354 for (final byte b : this.octets) {
355 if (builder.length() > 0) {
356 builder.append(".");
357 }
358 builder.append(String.format("%d", b & 0xff));
359 }
360 if (netmask != DEFAULT_MASK) {
361 builder.append("/");
362 builder.append(String.format("%d", netmask));
363 }
364 return builder.toString();
365 }
366
367}