blob: b09430db624f29abcda40ee0ee755160db1c273f [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 /**
194 * Helper for computing the mask value from CIDR.
195 *
196 * @return an integer bitmask
197 */
198 private int mask() {
199 int shift = MAX_INET_MASK - this.netmask;
200 return ((Integer.MAX_VALUE >>> (shift - 1)) << shift);
201 }
202
203 /**
204 * Returns the subnet mask in IpAddress form. The netmask value for
205 * the returned IpAddress is 0, as the address itself is a mask.
206 *
207 * @return the subnet mask
208 */
209 public IpAddress netmask() {
210 return new IpAddress(Version.INET, bytes(mask()));
211 }
212
213 /**
214 * Returns the network portion of this address as an IpAddress.
215 * The netmask of the returned IpAddress is the current mask. If this
216 * address doesn't have a mask, this returns an all-0 IpAddress.
217 *
218 * @return the network address or null
219 */
220 public IpAddress network() {
221 if (netmask == DEFAULT_MASK) {
222 return new IpAddress(version, ANY, DEFAULT_MASK);
223 }
224
225 byte [] net = new byte [4];
226 byte [] mask = bytes(mask());
227 for (int i = 0; i < INET_LEN; i++) {
228 net[i] = (byte) (octets[i] & mask[i]);
229 }
230 return new IpAddress(version, net, netmask);
231 }
232
233 /**
234 * Returns the host portion of the IPAddress, as an IPAddress.
235 * The netmask of the returned IpAddress is the current mask. If this
236 * address doesn't have a mask, this returns a copy of the current
237 * address.
238 *
239 * @return the host address
240 */
241 public IpAddress host() {
242 if (netmask == DEFAULT_MASK) {
243 new IpAddress(version, octets, netmask);
244 }
245
246 byte [] host = new byte [INET_LEN];
247 byte [] mask = bytes(mask());
248 for (int i = 0; i < INET_LEN; i++) {
249 host[i] = (byte) (octets[i] & ~mask[i]);
250 }
251 return new IpAddress(version, host, netmask);
252 }
253
254 public boolean isMasked() {
255 return mask() != 0;
256 }
257
258 /**
259 * Determines whether a given address is contained within this IpAddress'
260 * network.
261 *
262 * @param other another IP address that could be contained in this network
263 * @return true if the other IP address is contained in this address'
264 * network, otherwise false
265 */
266 public boolean contains(IpAddress other) {
267 if (this.netmask <= other.netmask) {
268 // Special case where they're both /32 addresses
269 if (this.netmask == MAX_INET_MASK) {
270 return Arrays.equals(octets, other.octets);
271 }
272
273 // Mask the other address with our network mask
274 IpAddress otherMasked =
275 IpAddress.valueOf(other.octets, netmask).network();
276
277 return network().equals(otherMasked);
278 }
279 return false;
280 }
281
282 @Override
283 public int hashCode() {
284 final int prime = 31;
285 int result = 1;
286 result = prime * result + netmask;
287 result = prime * result + Arrays.hashCode(octets);
288 result = prime * result + ((version == null) ? 0 : version.hashCode());
289 return result;
290 }
291
292 @Override
293 public boolean equals(Object obj) {
294 if (this == obj) {
295 return true;
296 }
297 if (obj == null) {
298 return false;
299 }
300 if (getClass() != obj.getClass()) {
301 return false;
302 }
303 IpAddress other = (IpAddress) obj;
304 if (netmask != other.netmask) {
305 return false;
306 }
307 if (!Arrays.equals(octets, other.octets)) {
308 return false;
309 }
310 if (version != other.version) {
311 return false;
312 }
313 return true;
314 }
315
316 @Override
317 /*
318 * (non-Javadoc)
319 * format is "x.x.x.x" for non-masked (netmask 0) addresses,
320 * and "x.x.x.x/y" for masked addresses.
321 *
322 * @see java.lang.Object#toString()
323 */
324 public String toString() {
325 final StringBuilder builder = new StringBuilder();
326 for (final byte b : this.octets) {
327 if (builder.length() > 0) {
328 builder.append(".");
329 }
330 builder.append(String.format("%d", b & 0xff));
331 }
332 if (netmask != DEFAULT_MASK) {
333 builder.append("/");
334 builder.append(String.format("%d", netmask));
335 }
336 return builder.toString();
337 }
338
339}