All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.googlecode.ipv6.IPv6Network Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2013 Jan Van Besien
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.googlecode.ipv6;

import java.math.BigInteger;
import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * Immutable representation of an IPv6 network based on an address and a prefix length. An IPv6 network is also an IPv6 address range (but
 * not all ranges are valid networks).
 *
 * @author Jan Van Besien
 */
public final class IPv6Network extends IPv6AddressRange
{
    public static final IPv6Network MULTICAST_NETWORK = fromString("ff00::/8");

    public static final IPv6Network SITE_LOCAL_NETWORK = fromString("fec0::/48");

    public static final IPv6Network LINK_LOCAL_NETWORK = fromString("fe80::/64");


    private final IPv6Address address;

    private final IPv6NetworkMask networkMask;

    /**
     * Construct from address and network mask.
     *
     * @param address     address
     * @param networkMask network mask
     */
    private IPv6Network(IPv6Address address, IPv6NetworkMask networkMask)
    {
        super(address.maskWithNetworkMask(networkMask), address.maximumAddressWithNetworkMask(networkMask));

        this.address = address.maskWithNetworkMask(networkMask);
        this.networkMask = networkMask;
    }

    /**
     * Create an IPv6 network from an IPv6Address and an IPv6NetworkMask
     *
     * @param address     IPv6 address (the network address or any other address within the network)
     * @param networkMask IPv6 network mask
     * @return IPv6 network
     */
    public static IPv6Network fromAddressAndMask(IPv6Address address, IPv6NetworkMask networkMask)
    {
        return new IPv6Network(address, networkMask);
    }

    /**
     * Create an IPv6 network from the two addresses within the network. This will construct the smallest possible network ("longest prefix
     * length") which contains both addresses.
     *
     * @param one address one
     * @param two address two, should be bigger than address one
     * @return ipv6 network
     */
    public static IPv6Network fromTwoAddresses(IPv6Address one, IPv6Address two)
    {
        final IPv6NetworkMask longestPrefixLength = IPv6NetworkMask.fromPrefixLength(IPv6NetworkHelpers.longestPrefixLength(one, two));
        return new IPv6Network(one.maskWithNetworkMask(longestPrefixLength), longestPrefixLength);
    }

    /**
     * Create an IPv6 network from its String representation. For example "1234:5678:abcd:0:0:0:0:0/64" or "2001::ff/128".
     *
     * @param string string representation
     * @return ipv6 network
     */
    public static IPv6Network fromString(String string)
    {
        if (string.indexOf('/') == -1)
        {
            throw new IllegalArgumentException("Expected format is network-address/prefix-length");
        }

        final String networkAddressString = parseNetworkAddress(string);
        int prefixLength = parsePrefixLength(string);

        final IPv6Address networkAddress = IPv6Address.fromString(networkAddressString);

        return fromAddressAndMask(networkAddress, new IPv6NetworkMask(prefixLength));
    }

    private static String parseNetworkAddress(String string)
    {
        return string.substring(0, string.indexOf('/'));
    }

    private static int parsePrefixLength(String string)
    {
        try
        {
            return Integer.parseInt(string.substring(string.indexOf('/') + 1));
        } catch (NumberFormatException e)
        {
            throw new IllegalArgumentException("Prefix length should be a positive integer");
        }
    }

    /**
     * Split a network in smaller subnets of a given size.
     *
     * @param size size (expressed as {@link com.googlecode.ipv6.IPv6NetworkMask}) of the subnets
     * @return iterator of the splitted subnets.
     * @throws IllegalArgumentException if the requested size is bigger than the original size
     */
    public Iterator split(IPv6NetworkMask size)
    {
        if (size.asPrefixLength() < this.getNetmask().asPrefixLength())
            throw new IllegalArgumentException(String.format("Can not split a network of size %s in subnets of larger size %s",
                                                             this.getNetmask().asPrefixLength(), size.asPrefixLength()));

        return new IPv6NetworkSplitsIterator(size);
    }

    @Override
    public String toString()
    {
        return address.toString() + "/" + networkMask.asPrefixLength();
    }

    /**
     * @return like toString but without using shorthand notations for addresses
     */
    public String toLongString()
    {
        return address.toLongString() + "/" + networkMask.asPrefixLength();
    }

    @Override
    public boolean equals(Object o)
    {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        if (!super.equals(o)) return false;

        IPv6Network that = (IPv6Network) o;

        if (address != null ? !address.equals(that.address) : that.address != null) return false;
        if (networkMask != null ? !networkMask.equals(that.networkMask) : that.networkMask != null) return false;

        return true;
    }

    @Override
    public int hashCode()
    {
        int result = super.hashCode();
        result = 31 * result + (address != null ? address.hashCode() : 0);
        result = 31 * result + (networkMask != null ? networkMask.hashCode() : 0);
        return result;
    }

    public IPv6NetworkMask getNetmask()
    {
        return networkMask;
    }

    private final class IPv6NetworkSplitsIterator implements Iterator
    {
        private final IPv6NetworkMask size;

        private IPv6Network current;

        private BigInteger nbrAddressesPerSplit;

        public IPv6NetworkSplitsIterator(IPv6NetworkMask size)
        {
            this.size = size;
            this.nbrAddressesPerSplit = BigInteger.ONE.shiftLeft(128 - size.asPrefixLength());
            this.current = IPv6Network.fromAddressAndMask(IPv6Network.this.address, size);
        }

        @Override
        public boolean hasNext()
        {
            return current.getLast().compareTo(IPv6Network.this.getLast()) <= 0;
        }

        @Override
        public IPv6Network next()
        {
            if (hasNext())
            {
                IPv6Network result = current;
                current = calculateNext(current);
                return result;
            }
            else
            {
                throw new NoSuchElementException();
            }
        }

        private IPv6Network calculateNext(IPv6Network current)
        {
            BigInteger next = current.address.toBigInteger().add(nbrAddressesPerSplit);
            return IPv6Network.fromAddressAndMask(IPv6Address.fromBigInteger(next), size);
        }

        @Override
        public void remove()
        {
            throw new UnsupportedOperationException("This iterator provides read only access");
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy