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