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