/* * This program 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. * * This program 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package freenet.io; import java.net.Inet6Address; import java.net.InetAddress; import java.util.Arrays; import java.util.StringTokenizer; import freenet.io.AddressIdentifier.AddressType; /** * @author David Roden <droden@gmail.com> * @version $Id$ */ public class Inet6AddressMatcher implements AddressMatcher { public AddressType getAddressType() { return AddressType.IPv6; } private static final byte[] FULL_MASK = new byte[16]; static { Arrays.fill(FULL_MASK, (byte) 0xff); } private byte[] address; private byte[] netmask; public Inet6AddressMatcher(String pattern) { if (pattern.indexOf('/') != -1) { address = convertToBytes(pattern.substring(0, pattern.indexOf('/'))); String netmaskString = pattern.substring(pattern.indexOf('/') + 1).trim(); if (netmaskString.indexOf(':') != -1) { netmask = convertToBytes(netmaskString); } else { netmask = new byte[16]; int bits = Integer.parseInt(netmaskString); if (bits > 128 || bits < 0) throw new IllegalArgumentException("Mask bits out of range: " + bits + " (" + netmaskString + ")"); for (int index = 0; index < 16; index++) { netmask[index] = (byte) (255 << (8 - Math.min(bits, 8))); bits = Math.max(bits - 8, 0); } } if(Arrays.equals(netmask, FULL_MASK)) netmask = FULL_MASK; } else { address = convertToBytes(pattern); netmask = FULL_MASK; } if (address.length != 16) { throw new IllegalArgumentException("address is not IPv6"); } } private byte[] convertToBytes(String address) { StringTokenizer addressTokens = new StringTokenizer(address, ":"); if (addressTokens.countTokens() != 8) { throw new IllegalArgumentException(address + " is not an IPv6 address."); } byte[] addressBytes = new byte[16]; int count = 0; while (addressTokens.hasMoreTokens()) { int addressWord = Integer.parseInt(addressTokens.nextToken(), 16); addressBytes[count * 2] = (byte) ((addressWord >> 8) & 0xff); addressBytes[count * 2 + 1] = (byte) (addressWord & 0xff); count++; } return addressBytes; } @Override public boolean matches(InetAddress address) { if (!(address instanceof Inet6Address)) return false; byte[] addressBytes = address.getAddress(); for (int index = 0; index < 16; index++) { if ((addressBytes[index] & netmask[index]) != (this.address[index] & netmask[index])) { return false; } } return true; } public static boolean matches(String pattern, InetAddress address) { return new Inet6AddressMatcher(pattern).matches(address); } @Override public String getHumanRepresentation() { if(netmask == FULL_MASK) return convertToString(address); else return convertToString(address)+'/'+convertToString(netmask); } private String convertToString(byte[] addr) { StringBuilder sb = new StringBuilder(4*8+7); for(int i=0;i<8;i++) { if(i != 0) sb.append(':'); int token = ((addr[i*2] & 0xff) << 8) + (addr[i*2+1] & 0xff); sb.append(Integer.toHexString(token)); } return sb.toString(); } }