Package com.slytechs.utils.net

Source Code of com.slytechs.utils.net.IpAddress

/**
* $Id$
*
* Copyright (C) 2006 Mark Bednarczyk, Sly Technologies, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place,
* Suite 330, Boston,
* MA 02111-1307 USA
*
*/
package com.slytechs.utils.net;

import java.net.InetAddress;
import java.net.UnknownHostException;

import com.slytechs.utils.io.DataBuffer;
import com.slytechs.utils.namespace.NameResolutionException;
import com.slytechs.utils.string.StringUtils;

/**
* A Class for storing IP Addresses Currently is only designed to utilize IPv4
* (32bit) addresses. Class also contains utility methods for DNS lookups. There
* are various functions for converting the IP address to a LONG. Why would you
* want to use a long for storage of an IP address, in my case I store IP
* address in a database as an UNSIGNED INT, java does not have unsigned numbers
* so you have to go to next bigger primitive type to store it or do like other
* implementations do store the address in a byte array.
*
* @author Mark Bednarczyk
* @author Sly Technologies, Inc.
*/
public class IpAddress extends Address {

 
  private static final long serialVersionUID = -7420353055502485516L;
 
  /**
   * <P>The version of IP Address. Only two versions exist 4 and 6.</P>
   *
   * <P>Version 4 addresses are made up of 4 bytes or 32 bits while version 6 addresses are
   * made up 16 bytes or 128 bits.</P>
   *
   * @author Mark Bednarczyk
   *
   */
  public enum IpAddressVersion {
   
    /**
     * IP version 4 address.
     */
    IpVersion4,
   
    /**
     * IP version 6 address.
     */
    IpVersion6,
    ;
   
    /**
     * Given an IP address lookup which version it is.
     *
     * @param address address, to lookup version for.
     * @return the version number for this IP address.
     */
    public static IpAddressVersion getIpAddressVersion(IpAddress address) {
      return getIpAddressVersion(address.toByteArray());
    }
   
    /**
     * Given an IP address lookup which version it is.
     *
     * @param address address, in big endian byte encoding, to lookup version for.
     * @return the version number for this IP address.
     */
    public static IpAddressVersion getIpAddressVersion(byte[] address) {
      if (address.length == 4) {
        return IpVersion4;
      } else {
        return IpVersion6;
      }
    }
  }
 
  /**
   * <P>Defines constants to describe the IP address routability through the internet as defined
   * by the internet com.slytechs.utils.info.standards using RFCs.</P>
   *
   * <P> There can be 3 types of addresses that are treated by routers differently.
   * <UL>
   <LI> Public addresses - normal IP Address that are fully routable
   *  <LI> Private addresses - addresses that can be used within a private network but will
   *  not be routed by Internet Service Provider or any of the internet routers.
   *  <LI> Automatic addresses - addresses which are used in place of DHCP servers for automatic
   *  configuration or network devices.
   * </UL>
   * </p>
   * @author Mark Bednarczyk
   *
   */
  public enum IpAddressRoutability {
   
    /**
     * True publically routable IP Address.
     */
    PublicAddress,
   
    /**
     * <P>(RFC1918) The following three IP ranges are reserved by
     * Internet Assigned Numbers Authority (IANA) according to RFC 1918. 
     * These IP addresses are not routable over the Internet, so they will
     * not conflict with other sites using these ranges.  To access the Internet
     * with these ranges, you need a Network Address Translation (NAT) device or
     * proxy server, etc.</P>
     *
     * <P> Private IP Addresses fall in the following ranges:
     * <UL>
     <LI> 10.0.0.0/8 - 10.255.255.255/12
     *  <LI> 172.16.0.0/12 - 172.31.255.255/12
     *  <LI> 192.168.0.0/16 - 192.168.255.255/16
     * </UL>
     * </P>
     */
    PrivateAddress      (new byte[][] {
        {10},
        {(byte)172, 16},
        {(byte)192, (byte)168}
    }),
   
    /**
     * <P>(RFC3330) This range is reserved as a Link Local Block for auto-configuration or
     * when a DHCP server can't be found. It is not recommended for normal
     * configuration but is useful in determining if a connection to a DHCP
     * server is not working.</P>
     */
    AutomaticAddress  (new byte[][] {
        {(byte)169, (byte)254
    })
    ;
   
    private final byte[][] addressList;

    private IpAddressRoutability() {
      this.addressList = null;
    }
   
    private IpAddressRoutability(byte[][] addressList) {
      this.addressList = addressList;
    }
   
    public boolean equals(byte[] address) {
     
      boolean res = true;
     
      if (addressList != null) {
       
        for(byte[] ba: this.addressList) {
         
          int i = 0;
          for(byte b: ba) {
            if (address[i++] != b) {
              res = false;
              break;
            }
           
            res = true;
          }
         
          if (res == true) {
            break;
          }
        } 
      }
     
      return res;
    }

  }
   
  /**
   * <P>Defines constants for various types of IP Addresses. IP Address can be looked up
   * for its type.<P>
   *
   * <P>For example, 0.0.0.0 is a BROADCAST address type, more specifically OldBroadcast type
   * since all 0 broadcasts are discouraged but still exist with existing legacy networks. Another
   * type of Address type is Unicast, meaning that an address is has an address that maps to
   * a single host.</P>
   *
   * <P>Other type of
   * @author Mark Bednarczyk
   *
   */
  public enum IpAddressType {
   
    /**
     * <P>IP Address consisting of all 0s. This is old style of broadcast addressing.</P>
     *
     * <P>Broadcast means that destination is all hosts reachable via the destination interface
     * of router, system, host or simply device.
     *
     */
    OldBroadcast (new byte[] {0, 0, 0, 0} ),
   
    /**
     * <P> IP Address consisting of all 1s or 255.255.255.255.</P>
     *
     * <P>Broadcast means that destination is all hosts reachable via the destination interface
     * of router, system, host or simply device.
     */
    Broadcast    (new byte[] {(byte)255, (byte)255, (byte)255, (byte)255} ),
   
    /**
     * <P>Device internal loopback interface for communication within its self. This is typeically
     * completely virtual interface created by routers, switches, systems for communication
     * with its internal sub-systems. Any device can create as many loopback interfaces as
     * they wish within the allocated address space.</P>
     *
     * <P>Address range for loopback addresses is:
     * <UL>
     <LI> 127.0.0.0/8 - 127.255.255.255/8
     * </UL>
     * </P>
     */
    Loopback     (new byte[][] {
        {127}
    }),
   
    /**
     * Multicast address type is destined to a group of devices.
     */
    Multicast(IpAddressClass.Multicast),
   
    /**
     * Unicast address type is bound signifies that there is a single device. Although
     * There are some tricky implementations of certain devices that make it look like a
     * single device when in reality multable devices communicate using the same Unicast address.
     */
    Unicast,
    ;
   
    private final byte[] address;
    private byte[][] addressList;
    private final IpAddressClass addressClass;
   
    private IpAddressType(IpAddressClass addressClass) {
      this.addressClass = addressClass;
      this.address = null;
      this.addressList = null;
    }

    private IpAddressType() {
      address = null;
      addressList = null;
      addressClass = null;
    }
   
    private IpAddressType(byte[] address) {
      this.address = address;
      this.addressClass = null;
    }
   
    private IpAddressType(byte[][] addressList) {
      this.address = null;
      this.addressList = addressList;
      this.addressClass = null;
    }
   
    /**
     * Tests the type of this address against this constant.
     *
     * @param address address to do a test against.
     * @return true if the supplied address is of this type, matching this constant
     * criteria, otherwise false.
     */
    public boolean equals(IpAddress address) {
      return equals(address.toByteArray());
    }
   
    /**
     * Tests the type of this address against this constant.
     *
     * @param address address, in big endian byte order encoding, to do a test against.
     * @return true if the supplied address is of this type, matching this constant
     * criteria, otherwise false.
     */
    public boolean equals(byte[] address) {
     
      if (address.length != 4) {
        return false;
      }
     
      if (this.address == null && this.addressList == null && this.addressClass == null) {
        return true;
      }
     
      if (this.addressClass != null) {
        return addressClass.equals(address);
      }
     
      if (this.address != null) {
        return AddressUtils.compare(this.address, address) == 0;
      } else {
       
        boolean res = true;
        for(byte[] ba: this.addressList) {
         
          int i = 0;
          for(byte b: ba) {
            if (address[i++] != b) {
              res = false;
              break;
            }
           
            res = true;
          }
         
          if (res == true) {
            break;
          }
        }
       
        return res;
      }
    }
   
    /**
     * Looks up the address against all defined types to which one the supplied
     * address belongs to.
     *
     * @param address address to lookup against all defined types.
     * @return type that best matches this address.
     */
    public static IpAddressType getAddressType(IpAddress address) {
      return getAddressType(address.toByteArray());
    }
   
    /**
     * Looks up the address against all defined types to which one the supplied
     * address belongs to.
     *
     * @param address address, in big endian byte encoding, to lookup against all defined types.
     * @return type that best matches this address.
     */
    public static IpAddressType getAddressType(byte[] address) {
      for(IpAddressType at: values()) {
        if (at.equals(address)) {
          return at;
        }
      }
     
      return Unicast;

    }
  }
   
  /**
   * <P>Defines Internet Protocol Address classes. Constants for prefix bits
   * and network mask for each class of IP address is provided via getter method
   * getPrefix() and getMask(). Also equals(IpAddress) method is provided to test if
   * supplied Ip address is part of this class.</P>
   *
   * @author Mark Bednarczyk
   *
   */
  public enum IpAddressClass {
   
    /**
     * <P>Address of this class is Class A address. All Ip v4 addresses
     * that begin with 00XX prefix are Class A.</P>
     *
     * <P>Range is from 0-127.H.H.H</P>
     *
     */
    ClassA    (0x00, 0x80),
   
    /**
     * <P>Address of this class is Class B address. All Ip v4 addresss
     * that begin with 10XX prefix are Class B.</P>
     *
     * <P>Range is from 128-191.N.H.H</P>
     *
     */
    ClassB    (0x80, 0xC0),
   
   
    /**
     * <P>Address of this class is Class C address. All Ip v4 addresss
     * that begin with 110X prefix are ClassCB.</P>
     *
     * <P>Range is from 192-223.N.N.H</P>
     *
     */
    ClassC    (0xC0, 0xE0),
   
    /**
     * <P>Address of this class is Class D (Multicast) address. All Ip v4 addresss
     * that begin with 10XX prefix are Class B.</P>
     *
     * <P>Range is from 224-247.H.H.H</P>
     *
     */
    Multicast (0xE0, 0xF0),
   
    /**
     * <P>Address of this class is Class D (Multicast) address. All Ip v4 addresss
     * that begin with 1110 prefix are Class B.</P>
     *
     * <P>Range is from 224-247.H.H.H</P>
     *
     */
    ClassD    (0xE0, 0xF0),
   
    /**
     * <P>Address of this class is Class E address. All Ip v4 addresss
     * that begin with 1111 prefix are Class E. Currently
     * Class E addresses are reserved and not in use.</P>
     *
     * <P>Range is from 248-255.H.H.H</P>
     *
     */
    ClassE    (0xF0, 0xF0),
    ;
   
    private final int prefix;
    private final int mask;

    /**
     * Construct our class enum constant using a prefix and mask.
     *
     * @param prefix prefix bits within the address that need to match.
     * @param mask mask which specifies which bits within the prefix are significant.
     */
    private IpAddressClass(int prefix, int mask) {
      this.prefix = prefix;
      this.mask = mask; 
    }
   
    /**
     * Getter to access the prefix defined for this address class. The prefix is that
     * first bits within the first byte of an IP Address that must match in order to fulfill
     * the Address class requirement.
     *
     * @return integer representing the prefix bits within the first byte (most significant) of IP address.
     */
    public int getPrefix() {
      return prefix;
    }
   
    /**
     * Getter to access the mask defined for this address class. The mask specifies which
     * bits within the prefix are significant and which are not (wild cards). When prefix is
     * applied to an address only the significant bits within this mask are used for comparison.
     *
     * @return integer representing the mask bits within the prefix.
     */
    public int getMask() {
      return mask;
    }
    /**
     * Tests against the supplied IP address for class equality.
     *
     * @param address address to test against this address class.
     * @return true if address is part of this class, otherwise false.
     */
    public boolean equals(IpAddress address) {
      return equals(address.toByteArray());
    }
   
    /**
     * Tests against the supplied IP address for class equality.
     *
     * @param address Ip address, in big endian byte order, to test against this address class.
     * @return true if address is part of this class, otherwise false.
     */
   
    public boolean equals(byte[] address) {
     
      if (address.length == 4) {
        return (AddressUtils.toInt(address[0]) & mask) == prefix;
      } else if (address.length == 16 && this == Multicast) {
        return (AddressUtils.toInt(address[0]) & mask) == prefix;
      } else {
        return false;
      }
    }
   
    /**
     * Given an IP address, returns the
     * specific IP Address class this address is part of.
     *
     * @param address Ip address, to test against
     * @return Address class for this address.
     */
    public static IpAddressClass getAddressClass(IpAddress address) {
      return getAddressClass(address.toByteArray());
    }

    /**
     * Given an IP address, returns the
     * specific IP Address class this address is part of.
     *
     * @param address Ip address, in big endian byte order, to test against
     * @return Address class for this address.
     */
    public static IpAddressClass getAddressClass(byte[] address) {
      for(IpAddressClass ac: values()) {
        if (ac.equals(address)) {
          return ac;
        }
      }
     
      return null;
    }
  }

  private InetAddress inetAddress = null;

  private String canonicalName = null;

  private String domainName = null;
 
  private String hostName = null;
 
  private IpAddressType addressType = null;
 
  private IpAddressClass addressClass = null;

  /**
   * Main constructor taking the array of bytes as the address. Automatically
   * sets the separator token between '.' and ':' depending on number of bytes
   * in the address. 4 bytes IPv4 address with '.' separator and 32 bytes for
   * IPv6 address with ':' as separator.
   *
   * @param address
   *            array of bytes making up the address.
   * @exception IllegalArgumentException
   *                if number of bytes is not 4 or 32.
   */
  public IpAddress(byte[] address) {
    super(address);

    if (address.length == 4)
      setSeparator('.');

    else if (address.length == 16) {
      setFormat("xx:xx:xx:xx:xx:xx:xx:xx");
      setRadix(16);
    }

    else {
      throw new IllegalArgumentException(
          "IP Address can only be either 32 or 128 bits long");
    }
  }

  /**
   * Constructor taking a canonicalName. This is a conveniece constructor which
   * converts the canonicalName to numerical format internally. Currently only IPv4
   * addresses can be initialized this way due to java.net library
   * limitations.
   *
   * @param canonicalName
   *            canonicalName or IP address in '.' notation initialize this address
   *            with.
   * @exception UnknownHostException
   *                if canonicalName can not be converted to an IP address.
   *                Addresses in IPv4 '.' notation format always convert and
   *                this exception is never thrown.
   */
  public IpAddress(Hostname hostname) throws NameResolutionException {

    try {
      inetAddress = InetAddress.getByName(hostname.getHostname());
    } catch (UnknownHostException e) {
      throw new NameResolutionException(e);
    }

    setAddress(inetAddress.getAddress());

    if (address.length == 4) {
      setSeparator('.');
    } else if (address.length == 16) {
      setFormat("xx:xx:xx:xx:xx:xx:xx:xx");
      setRadix(16);
    }
  }

  public IpAddress(String address) {
   
    setAddress(AddressUtils.toByteArray(address));
   
    if (address == null) {
      throw new IllegalArgumentException("Unrecognized IpAddress string [" + address + "]");
    }
   
    if (super.address.length == 4) {
      setSeparator('.');
    } else if (super.address.length == 16) {
      setFormat("xx:xx:xx:xx:xx:xx:xx:xx");
      setRadix(16);
    } else {
      throw new IllegalArgumentException("Unrecognized IpAddress string [" + address + "]");   
    }
  }

  public IpAddress(DataBuffer buffer) {
    super(buffer.getByte(4));
  }

  public IpAddress(DataBuffer buffer, int length) {
    super(buffer.getByte(length));
  }

  /**
   * Returns the java.net.InetAddress object associated with this IpAddress.
   *
   * @return InetAddress object associated with this IpAddress. If address
   *         does not exist and can not be resolved InetAddress object will be
   *         null and null will be returned as well.
   *
   * @since JNetStream 0.2.2
   */
  public InetAddress getInetObject() throws NameResolutionException {

    if (inetAddress == null)  {
      try {
        inetAddress = InetAddress.getByName(super.toString(false));

      } catch (UnknownHostException e) {
        throw new NameResolutionException(e);
      }
    }

    return inetAddress;
  }

  /**
   * Convert to dot notation string representation of the address. If canonicalName
   * is known then canonicalName.domain is returned other wise the appropriate
   * numerical representation of the numerical address is returned as a
   * String.
   *
   * @return IP address in the dot notation.
   */
  public String toString() {
    if (canonicalName != null) {
      return (canonicalName + "." + domainName);
    } else {
      return (super.toString());
    }
  }

  public IpAddressClass getAddressClass() {
   
    if (addressClass == null) {
      addressClass = IpAddressClass.getAddressClass(address);
    }
    return addressClass;
  }

  public IpAddressType getAddressType() {
    if (addressType == null) {
      addressType = IpAddressType.getAddressType(address);
    }
    return addressType;
  }

  public IpAddressVersion getAddressVersion() {
    return IpAddressVersion.getIpAddressVersion(this.address);
  }
  @Override
  public String getName() {
    return canonicalName;
  }

  @Override
  public boolean hasNameResolvingService() {
    return true;
  }

  @Override
  public boolean isNameResolved() {   
    return canonicalName != null;
  }

  public String getCanonicalHostname() {
    return canonicalName;
  }
 
  public String getHostname() {
    return hostName;
  }
 
  public String getDomainname() {
    return domainName;
  }
 
  @Override
  public boolean resolveName() throws NameResolutionException {
   
    if (canonicalName != null)
      return true;

    if (inetAddress == null) {
      try {
        inetAddress = InetAddress.getByName(super.toString(false));
      } catch (UnknownHostException e) {
        throw new NameResolutionException(e);
      }
    }

    canonicalName = inetAddress.getCanonicalHostName();
    hostName = inetAddress.getHostName();
   
    String[] path = canonicalName.split("\\.");
   
    if (path.length == 1) {
      domainName = "";
    } else {
      String s = "";
      for (int i = 0; i < path.length -1; i ++) {
        domainName += s + path[i];
        s = ".";
      }
    }
   

    if (canonicalName == null) {
      canonicalName = toString(false);
      hostName = canonicalName;
    }

    return true;
  }

  public static IpAddress valueOf(String address) {
    return new IpAddress(address);
  }

  public static IpAddress valueOf(Long address) {
    return new IpAddress(AddressUtils.toByteArray4Bytes(address));
  }

  public static boolean validateV4(String adr) {
    return adr.matches("[0..9]+\\.[0..9]+\\.[0..9]+\\.[0..9]+");
  }
 
  public static boolean validateV6(String adr) {
   
    int count = StringUtils.countChars(adr, ':');
    return count > 1;
  }
 
 
} /* END OF: IpAddress */
 
TOP

Related Classes of com.slytechs.utils.net.IpAddress

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.