Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-7132277

Failure to identify IPv4-Compatible Device Embedded IPv6 Address

XMLWordPrintable

    • x86
    • linux_redhat_5.0

      FULL PRODUCT VERSION :


      A DESCRIPTION OF THE PROBLEM :
      class java.net.InetAddress
      public static InetAddress getByAddress(String host, byte[] addr)

      uses sun.net.util.IPAddressUtil public static byte[] convertFromIPv4MappedAddress(byte[] addr)

      which uses the local method private static boolean isIPv4MappedAddress(byte[] addr)

      which is where the issue is. The 81-96 bits (11th and 12th array elements) are only ever checked to equal "(byte) 0xff", they should also be compared to "0x00"

      Please either fix IPAddressUtil or don't use it.


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------

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

      /**
       * <code>BugExample.java</code>
       */
      public class BugExample {

          public static void main(String[] args) throws UnknownHostException {

              byte[] ipv4CompatibleIpv6Address = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -64, -88, 1, 1 };
              byte[] ipv4MappedIpv6Address = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -64, -88, 1, 1 };

              // Fail
              InetAddress ipv4CompatibleIA = InetAddress.getByAddress( ipv4CompatibleIpv6Address );
              InetAddress ipv4MappedIA = InetAddress.getByAddress( ipv4MappedIpv6Address );

              System.out.println( "Fail" );
              System.out.println( "Should be '192.168.1.1' : " + ipv4CompatibleIA.getHostAddress() );
              System.out.println( "Should be '192.168.1.1' : " + ipv4MappedIA.getHostAddress() );


              // Fix
              // getByAddress checks for length == 4 then length == 16
              // leaving out because of local constructors and jumping to
      // } else if (addr.length == Inet6Address.INADDRSZ) {
      // byte[] newAddr = IPAddressUtil
      // .convertFromIPv4MappedAddress(addr);
              byte[] newAddrIpv4Compatible = convertFromIPv4MappedAddress(ipv4CompatibleIpv6Address);
              byte[] newAddrIpv4Mapped = convertFromIPv4MappedAddress(ipv4MappedIpv6Address);
              // from here it'll create and return a new Inet4Address if not null (which it won't be now),
              // but we'll just go and create a new InetAddress since we don't have easy access to the later.
              InetAddress fixedIpv4CompatibleIA = InetAddress.getByAddress( newAddrIpv4Compatible );
              InetAddress fixedIpv4MappedIA = InetAddress.getByAddress( newAddrIpv4Mapped );

              System.out.println( "Fix" );
              System.out.println( "Should be '192.168.1.1' : " + fixedIpv4CompatibleIA.getHostAddress() );
              System.out.println( "Should be '192.168.1.1' : " + fixedIpv4MappedIA.getHostAddress() );

          }
          
          
          private final static int INADDR16SZ = 16;
          /**
           * Utility routine to check if the InetAddress is an
           * IPv4 mapped IPv6 address.
           *
           * Modified to not only handle IPv4-Mapped IPv6 Addresses but also
           * IPv4-Compatible IPv6 Addresses (aka "dual-stack")
           * IPv4-Mapped IPv6 Address example: 0:0:0:0:0:0:0:FFFF:192.168.1.1
           * IPv4-Compatible IPv6 Address example: 0:0:0:0:0:0:0:0:192.168.1.1
           *
           * These modifications are in the isIPv4MappedAddress(byte[] addr) method where
           * we'll not check the 81st to 96th bits for either 00 or FF.
           *
           * From http://www.tcpipguide.com/free/t_IPv6IPv4AddressEmbedding.htm :
           * "The two embedding formats are used in order to indicate the
           * capabilities of the device using the embedded address."
           * The first 80 bits ( 10 signed ints, 5 hex values ) will always be 0.
           * The last 32 bits ( 4 signed ints, 2 hex value ) will be the IPv4 address.
           * If the "middle" 16 bits ( 2 signed ints, 1 hex value ) are 0's, then
           * the device was an IPv6-Compatible device. If instead those values are
           * FF's ( 255 ), then the device was not and was instead only IPv4-Capable.
           *
           * @return a <code>boolean</code> indicating if the InetAddress is
           * an IPv4 mapped IPv6 address; or false if address is IPv4 address.
           */
          private static boolean isIPv4MappedAddress(byte[] addr) {
              if (addr.length < INADDR16SZ) {
                  return false;
              }
              // Original code commented out:
      // if ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00)
      // && (addr[3] == 0x00) && (addr[4] == 0x00)
      // && (addr[5] == 0x00) && (addr[6] == 0x00)
      // && (addr[7] == 0x00) && (addr[8] == 0x00)
      // && (addr[9] == 0x00) && (addr[10] == (byte) 0xff)
      // && (addr[11] == (byte) 0xff)) {
      // return true;
      // }
              if ( (addr[0] == 0x00) && (addr[1] == 0x00)
                      && (addr[2] == 0x00) && (addr[3] == 0x00)
                      && (addr[4] == 0x00) && (addr[5] == 0x00)
                      && (addr[6] == 0x00) && (addr[7] == 0x00)
                      && (addr[8] == 0x00) && (addr[9] == 0x00) ) {
                  // Check if originating device was only IPv4 capable or
                  // if it was IPv6 compatible
                  if( ( ( addr[10] == (byte) 0xff ) && ( addr[11] == (byte) 0xff ) )
                          || ( ( addr[10] == 0x00 ) && ( addr[11] == 0x00 ) ) ) {
                      return true;
                  }
              }
              return false;
          }


          private final static int INADDR4SZ = 4;
          /*
           * Convert IPv4-Mapped address to IPv4 address. Both input and
           * returned value are in network order binary form.
           *
           * @param src a String representing an IPv4-Mapped address in textual format
           * @return a byte array representing the IPv4 numeric address
           */
          public static byte[] convertFromIPv4MappedAddress(byte[] addr) {
              if (isIPv4MappedAddress(addr)) {
                  byte[] newAddr = new byte[INADDR4SZ];
                  System.arraycopy(addr, 12, newAddr, 0, INADDR4SZ);
                  return newAddr;
              }
              return null;
          }



      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
          private static boolean isIPv4MappedAddress(byte[] addr) {
              if (addr.length < INADDR16SZ) {
                  return false;
              }
              // Original code commented out:
      // if ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00)
      // && (addr[3] == 0x00) && (addr[4] == 0x00)
      // && (addr[5] == 0x00) && (addr[6] == 0x00)
      // && (addr[7] == 0x00) && (addr[8] == 0x00)
      // && (addr[9] == 0x00) && (addr[10] == (byte) 0xff)
      // && (addr[11] == (byte) 0xff)) {
      // return true;
      // }
              if ( (addr[0] == 0x00) && (addr[1] == 0x00)
                      && (addr[2] == 0x00) && (addr[3] == 0x00)
                      && (addr[4] == 0x00) && (addr[5] == 0x00)
                      && (addr[6] == 0x00) && (addr[7] == 0x00)
                      && (addr[8] == 0x00) && (addr[9] == 0x00) ) {
                  // Check if originating device was only IPv4 capable or
                  // if it was IPv6 compatible
                  if( ( ( addr[10] == (byte) 0xff ) && ( addr[11] == (byte) 0xff ) )
                          || ( ( addr[10] == 0x00 ) && ( addr[11] == 0x00 ) ) ) {
                      return true;
                  }
              }
              return false;
          }

            Unassigned Unassigned
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Imported:
              Indexed: