/* * Copyright 2009-2014 Jagornet Technologies, LLC. All Rights Reserved. * * This software is the proprietary information of Jagornet Technologies, LLC. * Use is subject to license terms. * */ /* * This file Subnet.java is part of Jagornet DHCP. * * Jagornet DHCP 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 3 of the License, or * (at your option) any later version. * * Jagornet DHCP 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 Jagornet DHCP. If not, see <http://www.gnu.org/licenses/>. * */ package com.jagornet.dhcp.util; import java.math.BigInteger; import java.net.Inet4Address; import java.net.InetAddress; import java.net.UnknownHostException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Title: Subnet * Description: A utility class for managing IPv6 subnets. * * TODO: Refactor to use java.net.InterfaceAddress? * * @author A. Gregory Rabil */ public class Subnet implements Comparable<Subnet> { /** The log. */ private static Logger log = LoggerFactory.getLogger(Subnet.class); /** The subnet address. */ private InetAddress subnetAddress; private InetAddress endAddress; /** The prefix length. */ private int prefixLength; /** * Instantiates a new subnet. * * @param subnetAddress the subnet address * @param prefixLength the prefix length * * @throws UnknownHostException the unknown host exception * @throws NumberFormatException the number format exception */ public Subnet(String subnetAddress, String prefixLength) throws UnknownHostException, NumberFormatException { this(InetAddress.getByName(subnetAddress), Integer.parseInt(prefixLength)); } /** * Instantiates a new subnet. * * @param subnetAddress the subnet address * @param prefixLength the prefix length * * @throws UnknownHostException the unknown host exception * @throws NumberFormatException the number format exception */ public Subnet(String subnetAddress, int prefixLength) throws UnknownHostException, NumberFormatException { this(InetAddress.getByName(subnetAddress), prefixLength); } /** * Instantiates a new subnet. * * @param subnetAddress the subnet address * @param prefixLength the prefix length */ public Subnet(InetAddress subnetAddress, int prefixLength) { this.subnetAddress = subnetAddress; this.prefixLength = prefixLength; } /** * Gets the subnet address. * * @return the subnet address */ public InetAddress getSubnetAddress() { return subnetAddress; } /** * Sets the subnet address. * * @param subnetAddress the new subnet address */ public void setSubnetAddress(InetAddress subnetAddress) { this.subnetAddress = subnetAddress; } /** * Gets the prefix length. * * @return the prefix length */ public int getPrefixLength() { return prefixLength; } /** * Sets the prefix length. * * @param prefixLength the new prefix length */ public void setPrefixLength(int prefixLength) { this.prefixLength = prefixLength; } /** * Gets the end address. * * @return the end address */ public InetAddress getEndAddress() { if (endAddress == null) { int maxPrefix = 0; if (subnetAddress instanceof Inet4Address) { maxPrefix = 32; } else { maxPrefix = 128; } BigInteger start = new BigInteger(subnetAddress.getAddress()); // turn on each bit that isn't masked by the prefix // note that bit zero(0) is the lowest order bit, so // this loop logically moves from right to left for (int i=0; i<(maxPrefix-prefixLength); i++) { start = start.setBit(i); } try { endAddress = InetAddress.getByAddress(start.toByteArray()); } catch (UnknownHostException ex) { log.error("Failed to calculate subnet end address: " + ex); } } return endAddress; } /** * Contains. Test if an IP address falls within a subnet. * * @param inetAddr the IP address to check * * @return true, if subnet contains the IP address */ public boolean contains(InetAddress inetAddr) { boolean rc = false; BigInteger start = new BigInteger(getSubnetAddress().getAddress()); BigInteger end = new BigInteger(getEndAddress().getAddress()); BigInteger addr = new BigInteger(inetAddr.getAddress()); if ((addr.compareTo(start) >= 0) && (addr.compareTo(end) <= 0)) { rc = true; } return rc; } public int compareTo(Subnet that) { BigInteger thisAddr = new BigInteger(this.getSubnetAddress().getAddress()); BigInteger thatAddr = new BigInteger(that.getSubnetAddress().getAddress()); if (thisAddr.equals(thatAddr)) { Integer thisPrefix = this.getPrefixLength(); Integer thatPrefix = that.getPrefixLength(); // if we have two subnets with the same starting address // then the _smaller_ subnet is the one with the _larger_ // prefix length, which logically places the more specific // subnet _before_ the less specific subnet in the map // this allows us to work from "inside-out"? // must negate the comparison to make bigger smaller return -1 * thisPrefix.compareTo(thatPrefix); } else { // subnet addresses are different, so return // the standard compare for the address return thisAddr.compareTo(thatAddr); } } @Override public String toString() { StringBuilder sb = new StringBuilder(); if (subnetAddress != null) { sb.append(subnetAddress.getHostAddress()); sb.append('/'); sb.append(prefixLength); sb.append(" ("); sb.append(subnetAddress.getHostAddress()); sb.append('-'); sb.append(getEndAddress().getHostAddress()); sb.append(')'); } return sb.toString(); } }