Jonathan Hart

Created IpAddress class

1 +package org.onlab.packet;
2 +
3 +import 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 + */
11 +public 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 +}
...@@ -3,7 +3,9 @@ package org.onlab.packet; ...@@ -3,7 +3,9 @@ package org.onlab.packet;
3 import java.util.Arrays; 3 import java.util.Arrays;
4 4
5 /** 5 /**
6 - * A class representing an IPv4 address. 6 + * A class representing an IPv4 prefix.
7 + * <p/>
8 + * A prefix consists of an IP address and a subnet mask.
7 */ 9 */
8 public final class IpPrefix { 10 public final class IpPrefix {
9 11
......