001: /****************************************************************
002: * Licensed to the Apache Software Foundation (ASF) under one *
003: * or more contributor license agreements. See the NOTICE file *
004: * distributed with this work for additional information *
005: * regarding copyright ownership. The ASF licenses this file *
006: * to you under the Apache License, Version 2.0 (the *
007: * "License"); you may not use this file except in compliance *
008: * with the License. You may obtain a copy of the License at *
009: * *
010: * http://www.apache.org/licenses/LICENSE-2.0 *
011: * *
012: * Unless required by applicable law or agreed to in writing, *
013: * software distributed under the License is distributed on an *
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
015: * KIND, either express or implied. See the License for the *
016: * specific language governing permissions and limitations *
017: * under the License. *
018: ****************************************************************/package org.apache.james.jspf.core;
019:
020: import java.util.ArrayList;
021: import java.util.StringTokenizer;
022:
023: /**
024: * Utility functions for IPV6 operations.
025: *
026: * see Inet6Util from the Apache Harmony project
027: *
028: * see org.apache.harmony.util.Inet6Util
029: */
030: public class Inet6Util {
031:
032: private Inet6Util() {
033: // make this class a an utility class non-instantiable
034: }
035:
036: /**
037: * Creates an byte[] based on an ipAddressString. No error handling is
038: * performed here.
039: */
040: public static byte[] createByteArrayFromIPAddressString(
041: String ipAddressString) {
042:
043: if (isValidIPV4Address(ipAddressString)) {
044: StringTokenizer tokenizer = new StringTokenizer(
045: ipAddressString, ".");
046: String token = "";
047: int tempInt = 0;
048: byte[] byteAddress = new byte[4];
049: for (int i = 0; i < 4; i++) {
050: token = tokenizer.nextToken();
051: tempInt = Integer.parseInt(token);
052: byteAddress[i] = (byte) tempInt;
053: }
054:
055: return byteAddress;
056: }
057:
058: if (ipAddressString.charAt(0) == '[') {
059: ipAddressString = ipAddressString.substring(1,
060: ipAddressString.length() - 1);
061: }
062:
063: StringTokenizer tokenizer = new StringTokenizer(
064: ipAddressString, ":.", true);
065: ArrayList hexStrings = new ArrayList();
066: ArrayList decStrings = new ArrayList();
067: String token = "";
068: String prevToken = "";
069: int doubleColonIndex = -1; // If a double colon exists, we need to
070: // insert 0s.
071:
072: // Go through the tokens, including the seperators ':' and '.'
073: // When we hit a : or . the previous token will be added to either
074: // the hex list or decimal list. In the case where we hit a ::
075: // we will save the index of the hexStrings so we can add zeros
076: // in to fill out the string
077: while (tokenizer.hasMoreTokens()) {
078: prevToken = token;
079: token = tokenizer.nextToken();
080:
081: if (token.equals(":")) {
082: if (prevToken.equals(":")) {
083: doubleColonIndex = hexStrings.size();
084: } else if (!prevToken.equals("")) {
085: hexStrings.add(prevToken);
086: }
087: } else if (token.equals(".")) {
088: decStrings.add(prevToken);
089: }
090: }
091:
092: if (prevToken.equals(":")) {
093: if (token.equals(":")) {
094: doubleColonIndex = hexStrings.size();
095: } else {
096: hexStrings.add(token);
097: }
098: } else if (prevToken.equals(".")) {
099: decStrings.add(token);
100: }
101:
102: // figure out how many hexStrings we should have
103: // also check if it is a IPv4 address
104: int hexStringsLength = 8;
105:
106: // If we have an IPv4 address tagged on at the end, subtract
107: // 4 bytes, or 2 hex words from the total
108: if (decStrings.size() > 0) {
109: hexStringsLength -= 2;
110: }
111:
112: // if we hit a double Colon add the appropriate hex strings
113: if (doubleColonIndex != -1) {
114: int numberToInsert = hexStringsLength - hexStrings.size();
115: for (int i = 0; i < numberToInsert; i++) {
116: hexStrings.add(doubleColonIndex, "0");
117: }
118: }
119:
120: byte ipByteArray[] = new byte[16];
121:
122: // Finally convert these strings to bytes...
123: for (int i = 0; i < hexStrings.size(); i++) {
124: convertToBytes((String) hexStrings.get(i), ipByteArray,
125: i * 2);
126: }
127:
128: // Now if there are any decimal values, we know where they go...
129: for (int i = 0; i < decStrings.size(); i++) {
130: ipByteArray[i + 12] = (byte) (Integer
131: .parseInt((String) decStrings.get(i)) & 255);
132: }
133:
134: // now check to see if this guy is actually and IPv4 address
135: // an ipV4 address is ::FFFF:d.d.d.d
136: boolean ipV4 = true;
137: for (int i = 0; i < 10; i++) {
138: if (ipByteArray[i] != 0) {
139: ipV4 = false;
140: break;
141: }
142: }
143:
144: if (ipByteArray[10] != -1 || ipByteArray[11] != -1) {
145: ipV4 = false;
146: }
147:
148: if (ipV4) {
149: byte ipv4ByteArray[] = new byte[4];
150: for (int i = 0; i < 4; i++) {
151: ipv4ByteArray[i] = ipByteArray[i + 12];
152: }
153: return ipv4ByteArray;
154: }
155:
156: return ipByteArray;
157:
158: }
159:
160: /** Converts a 4 character hex word into a 2 byte word equivalent */
161: public static void convertToBytes(String hexWord,
162: byte ipByteArray[], int byteIndex) {
163:
164: int hexWordLength = hexWord.length();
165: int hexWordIndex = 0;
166: ipByteArray[byteIndex] = 0;
167: ipByteArray[byteIndex + 1] = 0;
168: int charValue;
169:
170: // high order 4 bits of first byte
171: if (hexWordLength > 3) {
172: charValue = getIntValue(hexWord.charAt(hexWordIndex++));
173: ipByteArray[byteIndex] = (byte) (ipByteArray[byteIndex] | (charValue << 4));
174: }
175:
176: // low order 4 bits of the first byte
177: if (hexWordLength > 2) {
178: charValue = getIntValue(hexWord.charAt(hexWordIndex++));
179: ipByteArray[byteIndex] = (byte) (ipByteArray[byteIndex] | charValue);
180: }
181:
182: // high order 4 bits of second byte
183: if (hexWordLength > 1) {
184: charValue = getIntValue(hexWord.charAt(hexWordIndex++));
185: ipByteArray[byteIndex + 1] = (byte) (ipByteArray[byteIndex + 1] | (charValue << 4));
186: }
187:
188: // low order 4 bits of the first byte
189: charValue = getIntValue(hexWord.charAt(hexWordIndex));
190: ipByteArray[byteIndex + 1] = (byte) (ipByteArray[byteIndex + 1] | charValue & 15);
191: }
192:
193: static int getIntValue(char c) {
194:
195: switch (c) {
196: case '0':
197: return 0;
198: case '1':
199: return 1;
200: case '2':
201: return 2;
202: case '3':
203: return 3;
204: case '4':
205: return 4;
206: case '5':
207: return 5;
208: case '6':
209: return 6;
210: case '7':
211: return 7;
212: case '8':
213: return 8;
214: case '9':
215: return 9;
216: }
217:
218: c = Character.toLowerCase(c);
219: switch (c) {
220: case 'a':
221: return 10;
222: case 'b':
223: return 11;
224: case 'c':
225: return 12;
226: case 'd':
227: return 13;
228: case 'e':
229: return 14;
230: case 'f':
231: return 15;
232: }
233: return 0;
234: }
235:
236: public static boolean isValidIP6Address(String ipAddress) {
237: int length = ipAddress.length();
238: boolean doubleColon = false;
239: int numberOfColons = 0;
240: int numberOfPeriods = 0;
241: int numberOfPercent = 0;
242: String word = "";
243: char c = 0;
244: char prevChar = 0;
245: int offset = 0; // offset for [] ip addresses
246:
247: if (length < 2)
248: return false;
249:
250: for (int i = 0; i < length; i++) {
251: prevChar = c;
252: c = ipAddress.charAt(i);
253: switch (c) {
254:
255: // case for an open bracket [x:x:x:...x]
256: case '[':
257: if (i != 0)
258: return false; // must be first character
259: if (ipAddress.charAt(length - 1) != ']')
260: return false; // must have a close ]
261: offset = 1;
262: if (length < 4)
263: return false;
264: break;
265:
266: // case for a closed bracket at end of IP [x:x:x:...x]
267: case ']':
268: if (i != length - 1)
269: return false; // must be last charcter
270: if (ipAddress.charAt(0) != '[')
271: return false; // must have a open [
272: break;
273:
274: // case for the last 32-bits represented as IPv4 x:x:x:x:x:x:d.d.d.d
275: case '.':
276: numberOfPeriods++;
277: if (numberOfPeriods > 3)
278: return false;
279: if (!isValidIP4Word(word))
280: return false;
281: if (numberOfColons != 6 && !doubleColon)
282: return false;
283: // a special case ::1:2:3:4:5:d.d.d.d allows 7 colons with an
284: // IPv4 ending, otherwise 7 :'s is bad
285: if (numberOfColons == 7
286: && ipAddress.charAt(0 + offset) != ':'
287: && ipAddress.charAt(1 + offset) != ':')
288: return false;
289: word = "";
290: break;
291:
292: case ':':
293: // FIX "IP6 mechanism syntax #ip6-bad1"
294: // An IPV6 address cannot start with a single ":".
295: // Either it can starti with "::" or with a number.
296: if (i == offset
297: && (ipAddress.length() <= i || ipAddress
298: .charAt(i + 1) != ':')) {
299: return false;
300: }
301: // END FIX "IP6 mechanism syntax #ip6-bad1"
302: numberOfColons++;
303: if (numberOfColons > 7)
304: return false;
305: if (numberOfPeriods > 0)
306: return false;
307: if (prevChar == ':') {
308: if (doubleColon)
309: return false;
310: doubleColon = true;
311: }
312: word = "";
313: break;
314: case '%':
315: if (numberOfColons == 0)
316: return false;
317: numberOfPercent++;
318:
319: // validate that the stuff after the % is valid
320: if ((i + 1) >= length) {
321: // in this case the percent is there but no number is
322: // available
323: return false;
324: }
325: try {
326: Integer.parseInt(ipAddress.substring(i + 1));
327: } catch (NumberFormatException e) {
328: // right now we just support an integer after the % so if
329: // this is not
330: // what is there then return
331: return false;
332: }
333: break;
334:
335: default:
336: if (numberOfPercent == 0) {
337: if (word.length() > 3)
338: return false;
339: if (!isValidHexChar(c))
340: return false;
341: }
342: word += c;
343: }
344: }
345:
346: // Check if we have an IPv4 ending
347: if (numberOfPeriods > 0) {
348: if (numberOfPeriods != 3 || !isValidIP4Word(word))
349: return false;
350: } else {
351: // If we're at then end and we haven't had 7 colons then there is a
352: // problem unless we encountered a doubleColon
353: if (numberOfColons != 7 && !doubleColon) {
354: return false;
355: }
356:
357: // If we have an empty word at the end, it means we ended in either
358: // a : or a .
359: // If we did not end in :: then this is invalid
360: if (numberOfPercent == 0) {
361: if (word == ""
362: && ipAddress.charAt(length - 1 - offset) == ':'
363: && ipAddress.charAt(length - 2 - offset) != ':') {
364: return false;
365: }
366: }
367: }
368:
369: return true;
370: }
371:
372: public static boolean isValidIP4Word(String word) {
373: char c;
374: if (word.length() < 1 || word.length() > 3)
375: return false;
376: for (int i = 0; i < word.length(); i++) {
377: c = word.charAt(i);
378: if (!(c >= '0' && c <= '9'))
379: return false;
380: }
381: if (Integer.parseInt(word) > 255)
382: return false;
383: return true;
384: }
385:
386: static boolean isValidHexChar(char c) {
387:
388: return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')
389: || (c >= 'a' && c <= 'f');
390: }
391:
392: /**
393: * Takes a string and parses it to see if it is a valid IPV4 address.
394: *
395: * @return true, if the string represents an IPV4 address in dotted
396: * notation, false otherwise
397: */
398: public static boolean isValidIPV4Address(String value) {
399:
400: int periods = 0;
401: int i = 0;
402: int length = value.length();
403:
404: if (length > 15)
405: return false;
406: char c = 0;
407: String word = "";
408: for (i = 0; i < length; i++) {
409: c = value.charAt(i);
410: if (c == '.') {
411: periods++;
412: if (periods > 3)
413: return false;
414: if (word == "")
415: return false;
416: if (Integer.parseInt(word) > 255)
417: return false;
418: word = "";
419: } else if (!(Character.isDigit(c)))
420: return false;
421: else {
422: if (word.length() > 2)
423: return false;
424: word += c;
425: }
426: }
427:
428: if (word == "" || Integer.parseInt(word) > 255)
429: return false;
430: if (periods != 3)
431: return false;
432: return true;
433: }
434:
435: }
|