/* * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * Free SoftwareFoundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */ package com.caucho.util; import java.util.logging.*; import java.net.InetAddress; /** * Represents an internet network mask. */ public class InetNetwork { private static final Logger log = Logger.getLogger(InetNetwork.class.getName()); private long _address; private long _mask; private int _maskIndex; /** * Create a internet mask. * * @param inetAddress the main address * @param maskIndex the number of bits to match. */ public InetNetwork(InetAddress inetAddress, int maskIndex) { byte []bytes = inetAddress.getAddress(); long address = 0; for (int i = 0; i < bytes.length; i++) address = 256 * address + (bytes[i] & 0xff); _address = address; _maskIndex = maskIndex; _mask = -1L << (8 * bytes.length - maskIndex); } /** * Creates an inet network with a mask. */ public InetNetwork(long address, int maskIndex) { _address = address; _maskIndex = maskIndex; _mask = -1L << (32 - maskIndex); } /** * Creates an inet network with a mask. */ public InetNetwork(long hiAddress, long loAddress, int maskIndex) { _address = loAddress; _maskIndex = maskIndex; _mask = -1L << (64 - maskIndex); } public static InetNetwork valueOf(String network) { return create(network); } public static InetNetwork create(String network) { if (network == null) return null; int i = 0; int len = network.length(); if (network.indexOf(':') >= 0) return createIPv6(network); long address = 0; int digits = 0; int ch = 0; while (i < len) { if (network.charAt(i) == '/') break; int digit = 0; for (; i < len && '0' <= (ch = network.charAt(i)) && ch <= '9'; i++) digit = 10 * digit + ch - '0'; address = 256 * address + digit; digits++; if (i < len && ch == '.') i++; else if (i < len) break; } int mask = 8 * digits; for (; digits < 4; digits++) { address *= 256; } if (i < len && network.charAt(i) == '/') { mask = 0; for (i++; i < len && '0' <= (ch = network.charAt(i)) && ch <= '9'; i++) mask = 10 * mask + ch - '0'; } return new InetNetwork(address, mask); } public static InetNetwork createIPv6(String network) { int i = 0; int len = network.length(); long hi = 0; long lo = 0; long topHi = 0; long topLo = 0; int digits = 0; boolean isIPv4 = false; int ch = 0; while (i < len) { ch = network.charAt(i); if (ch == '/') break; int digit = 0; for (; i < len; i++) { ch = network.charAt(i); int v = 0; if ('0' <= ch && ch <= '9') v = ch - '0'; else if ('a' <= ch && ch <= 'f') v = ch - 'a'; else if ('A' <= ch && ch <= 'F') v = ch - 'A'; else break; if (isIPv4) digit = 10 * digit + v; else digit = 16 * digit + v; } if (ch == '.' && ! isIPv4) { digit = (digit / 256) * 100 + (digit / 16 % 16) * 10 + digit % 16; isIPv4 = true; } if (isIPv4) { hi = (hi << 8) + (lo >> 56); lo = (lo << 8) + digit; digits++; } else { hi = (hi << 16) + (lo >> 48); lo = (lo << 16) + digit; digits += 2; } if (len <= i) break; else if (ch == '/') break; else if (ch == '.') i++; else if (ch == ':' && i + 1 < len && network.charAt(i + 1) == ':') { i += 2; int shift = 16 - digits; topHi += hi << (8 * shift); if (shift < 8) topHi += lo >> (8 * (8 - shift)); else topHi += lo << 8 * (shift - 8); hi = 0; lo = 0; } else if (ch == ':') i++; else break; } hi += topHi; lo += topLo; int mask = 64; if (i < len && network.charAt(i) == '/') { mask = 0; for (i++; i < len && (ch = network.charAt(i)) >= '0' && ch <= '9'; i++) mask = 10 * mask + ch - '0'; } return new InetNetwork(hi, lo, mask); } /** * Returns true if the address is in this network. */ public boolean isMatch(InetAddress inetAddress) { byte []bytes = inetAddress.getAddress(); long address = 0; for (int i = 0; i < bytes.length; i++) address = 256 * address + (bytes[i] & 0xff); return (_address & _mask) == (address & _mask); } /** * Returns true if the address is in this network. */ public boolean isMatch(byte []bytes) { long address = 0; for (int i = 0; i < bytes.length; i++) address = 256 * address + (bytes[i] & 0xff); return (_address & _mask) == (address & _mask); } /** * Returns true if the address is in this network. */ public boolean isMatch(String address) { try { return isMatch(InetAddress.getByName(address)); } catch (Exception e) { log.log(Level.FINER, e.toString(), e); return false; } } /** * Returns true if the address is in this network. */ public boolean isMatch(long address) { return (_address & _mask) == (address & _mask); } /** * Return a readable string. */ public String toString() { StringBuilder cb = new StringBuilder(); for (int i = 0; i < 4; i++) { if (i != 0) cb.append('.'); cb.append((_address >> (3 - i) * 8) & 0xff); } cb.append('/'); cb.append(_maskIndex); return cb.toString(); } }