experts.net.ip6.ULUA.java Source code

Java tutorial

Introduction

Here is the source code for experts.net.ip6.ULUA.java

Source

/*
 * Experts Net
 * Copyright (c) 2014-2017 Makoto Sakaguchi.
 *
 * 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 3 of the License, or
 * 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, see <http://www.gnu.org/licenses/>.
 */
package experts.net.ip6;

import java.io.IOException;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.net.ntp.NTPUDPClient;
import org.apache.commons.net.ntp.NtpV3Packet;
import org.apache.commons.net.ntp.TimeInfo;

/**
 * Unique Local IPv6 Unicast Addresses (RFC 4193)
 *
 * @author Makoto Sakaguchi
 * @version 2.0.6-dev
 */
public class ULUA extends IP6 {
    private final int GLOBAL_ID_LENGTH = 3;
    private final String GLOBAL_ID_PREFIX_FORMAT = "fd";
    private final byte GLOBAL_ID_PREFIX = (byte) 0xfd;

    private final short DEFAULT_SUBNT_ID = 0x0000;

    private final int INTERFACE_ID_LENGTH = 8;
    private final short ADDITIONAL_VALUES = (short) 0xfffe;

    private final String NTP_SERVER_ADDRESS = "pool.ntp.org";

    /**
     * Constructor that takes address of the machine.
     *
     * @param address
     *            a MAC address of the machine that creates Unique Local IPv6 Unicast Addresses
     * @throws SocketException
     * @throws UnknownHostException
     * @throws IOException
     */
    public ULUA(byte[] address) throws SocketException, UnknownHostException, IOException {
        createInterfaceIDByEUI64(address);
        subnetID = Arrays.asList(DEFAULT_SUBNT_ID);
        generateGlobalID(obtainNTPTime(NTP_SERVER_ADDRESS));
    }// ULUA(String address)

    /**
     * @param gID
     *            a global ID field of the ULUA, the prefix (0xfd00::/8) and Global ID
     * @see experts.net.ip6.IP6Utils#setGlobalID(java.lang.String)
     */
    @Override
    public void setGlobalID(String gID) {
        String[] tmp = gID.toLowerCase().split(":");

        // Check length
        if (tmp.length > GLOBAL_ID_LENGTH) {
            throw new IllegalArgumentException("The length of the prefix and Global ID of ULUA must be 48 bits.");
        } // if

        // Check prefix
        if (!tmp[0].startsWith(GLOBAL_ID_PREFIX_FORMAT)) {
            throw new IllegalArgumentException("ULUA must be 0xfd00::/8.");
        } // if

        /*
         * Check prefix by short value
         * tmp is a short array
         *
         * (byte) (tmp.get(0) & 0xff00) != GLOBAL_ID_PREFIX ? throw new IllegalArgumentException("ULUA must be 0xfd00::/8.");
         */
        globalID = IP6Utils.toShortList(tmp);
    }// setGlobalID

    /**
     * @param Subnet
     *            ID of the ULUA
     * @see experts.net.ip6.IP6Utils#setSubnetID(int)
     */
    @Override
    public void setSubnetID(String sID) {
        subnetID = Arrays.asList((short) Integer.parseInt(sID, 16));
    }// setSubnetID

    /**
     * @param Interface
     *            ID of the ULUA
     * @see experts.net.ip6.IP6Utils#setInterfaceID(java.lang.String)
     */
    @Override
    public void setInterfaceID(String iID) {
        String[] tmp = iID.split(":");

        // Check length
        if (tmp.length > INTERFACE_ID_LENGTH) {
            throw new IllegalArgumentException("The Interface ID length of ULUA must be 64 bits.");
        } // if

        interfaceID = IP6Utils.toShortList(tmp);
    }// setInterfaceID

    /**
     * Obtain NTP time stamp value
     *
     * @param address
     *            NTP server address
     * @return the current time of day in 64-bit NTP format
     * @throws SocketException
     *             If the socket could not be opened which it might be not available any ports.
     * @throws UnknownHostException
     *             If the host could not be found.
     * @throws IOException
     */
    public static long obtainNTPTime(String address) throws SocketException, UnknownHostException, IOException {
        NTPUDPClient client = new NTPUDPClient();
        client.setVersion(NtpV3Packet.VERSION_4);

        // throws SocketException
        client.open();
        // throws UnknownHostException from InetAddress.getByName and IOException from client.getTime
        TimeInfo time = client.getTime(InetAddress.getByName(address));
        client.close();

        time.computeDetails();

        return time.getMessage().getTransmitTimeStamp().ntpValue();
    }// obtainNTPTime

    /**
     * Generate Global ID according to RFC 4193 Section 3.2.2.
     *
     * @param timeStamp
     *            64-bit NTP format
     */
    public final void generateGlobalID(long timeStamp) {
        ByteBuffer buf = ByteBuffer.allocate(16);

        buf.putLong(timeStamp);
        interfaceID.forEach(buf::putShort);

        byte[] digest = DigestUtils.sha1(buf.array());

        buf = ByteBuffer.allocate(6);
        buf.put(GLOBAL_ID_PREFIX).put(digest, 15, 5);

        globalID = toList(buf);
    }// generateGlobalID

    /**
     * Create Interface ID by the Modified EUI-64 format (RFC 4291)
     *
     * @param macAddr
     *            MAC (NIC) address
     */
    public final void createInterfaceIDByEUI64(byte[] macAddr) {
        ByteBuffer buf = ByteBuffer.allocate(INTERFACE_ID_LENGTH);

        buf.put(macAddr, 0, 3).putShort(ADDITIONAL_VALUES).put(macAddr, 3, 3);

        buf.put(0, (byte) (buf.get(0) ^ 0x02));

        interfaceID = toList(buf);
    }// createInterfaceIDByEUI64

    /**
     * Convert ByteBuffer to Short List
     *
     * @param buf
     *            ByteBuffer
     * @return Short List
     */
    private static List<Short> toList(ByteBuffer buf) {
        int cap = buf.capacity() / 2;
        List<Short> tmp = new ArrayList<>(cap);

        buf.rewind();
        for (int i = 0; i < cap; i++) {
            tmp.add(buf.getShort());
        } // for

        return tmp;
    }// toList
}