Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

Subnetting with IPv6 - Part 2/2

4.95/5 (45 votes)
24 May 2022BSD6 min read 106.5K   5.6K  
IPv6 Subnet Calculator / Tool explained ( latest version: 5.0 )
In the second part of the article, I will try to explain functions I used inside the application together with a technique for how to find adjacent subnets. In this article we check the entered value to see either the user entered a valid IPv6 address or not, we figure out how can we move or walk through the adjacent subnet address spaces, and we also handle finding the index value in our application.

C# Screenshots

Image 1

Image 2

Image 3

Java Screenshot

 

Image 4

 

Introduction

In the second part of the article, I will try to explain functions I used inside the application together with a technique for how to find adjacent subnets.

(Follow the link for the first part of this article: Subnetting with IPv6 Part 1/2[^] )

About this Application

First, start by checking the entered value to see either the user entered a valid IPv6 address or not. For this purpose, the function IsAddressCorrect() gets the entered string, and does the necessary checks on it, and returns either 'true' or 'false' boolean value depending on the check result.

Java
public boolean IsAddressCorrect(String sin) {
    int nDC = 0;
    int nC = 0;

    sin = sin.trim();
    String s = sin;
    char[] chars = s.toCharArray();

    /* 0. Error: Empty */
    if (s.isEmpty()) {
        errmsg = "> Empty address";
        return false;
    }


    /* 1. Error: UNDEFINED '::' */
    if (s.equals("::")) {
        errmsg = "> Undefined";
        return false;
    }
    /* 2. Error: Triple or more colons entered */
    if ((s.length() <= 1) || (s.contains(":::"))) {
        errmsg = "> Not valid";
        return false;
    }
    /* 3. Error: Not valid hex */
    if (!Pattern.matches("^[0-9A-Fa-f:]+$", s)) {
        errmsg = "> Not valid hex-digit";
        return false;
    }
    /* 4. Error: Cannot start or end with ':' */
    if (chars[0] == ':' && chars[1] != ':') {
        errmsg = "> Not valid: ':'";
        return false;
    }
    if (chars[s.length() - 1] == ':' && chars[s.length() - 2] != ':') {
        errmsg = "> Not valid: ':'";
        return false;
    }
    /* 5. Error: More than 2 Bytes */
    String[] sa = s.split(":", -1);
    for (int j = 0; j < sa.length; j++) {
        if (sa[j].length() > 4) {
            errmsg = "> More than 2 bytes";
            return false;
        }
    }
    /* 6. Error: Number of DoubleColons and Colons */
    s = sin;
    nDC = s.split("::", -1).length - 1;
    s = s.replace("::", "**");
    nC = s.split(":", -1).length - 1;

    /* Case I. DoubleColon can only appear once - RFC4291 */
    if (nDC > 1) {
        errmsg = "> DoubleColon can only appear once";
        return false;
    }
    /* Case II. No DoubleColon means there must be 7 colons */
    if (nDC == 0 && nC != 7) {
        errmsg = "> Not valid, there must be 7 colons";
        return false;
    }
    /* Case III. If DoubleColon at start/end, max. colons must be 6 or less */
    s = sin;
    int sL = s.length();
    if ((chars[0] == ':' && chars[1] == ':')
            || (chars[sL - 1] == ':' && chars[sL - 2] == ':')) {
        if (nDC == 1 && nC > 6) {
            errmsg = "> Excessive colons";
            return false;
        }
    } /* Case IV. If DoubleColon in middle, max. colons must be 5 or less
       */ 
    else if (nDC == 1 && nC > 5) {
        errmsg = "> Excessive colons";
        return false;
    }


    /* End of Check */
    errmsg = "> ok";
    return true;
} 

If the entered value is a valid IPv6 address, then we need to formalize the entered address into 16 Bytes hexadecimal value in order to perform our calculations on it. The function FormalizeAddress() gets a valid IPv6 address as string, places the necessary amount of zeros if the address is compressed, and then returns 16 Bytes formal IPv6 address as BigInteger data type.

Java
public BigInteger FormalizeAddr(String sin) {
 
    String[] Resv6 = new String[]{"0000", "0000", "0000",
                                  "0000", "0000", "0000",
                                  "0000", "0000"};
 
    BigInteger Finalv6 = BigInteger.ZERO;
    sin = sin.trim();
    String s = sin;
    String[] sa = s.split(":", -1);
    int nC = 0;
    s = s.replace("::", "**");
    nC = s.split(":", -1).length - 1;

    /* Start of Building Result v6 address */
   for (int k = 0; k < sa.length; k++) {
       if (sa[k].length() == 0) {
           continue;
       } else {
            sa[k] = String.format("%4s", sa[k]).replace(' ', '0');
       }
   }

   if ((sa[sa.length - 1].length() == 0) 
       && (sa[sa.length - 2].length() == 0)) {
       int t = nC + 1;
       for (int i = 0; i < t; i++) {
          Resv6[i] = sa[i];
       } 
   } else if (sa[0].length() == 0 && sa[1].length() == 0) { 
       int t = nC + 1; 
       for (int i = 0; i < t; i++) {
          Resv6[7 - i] = sa[sa.length - 1 - i];
       }
   } else {
       int idx = Arrays.asList(sa).indexOf("");
       for (int i = 0; i < idx; i++) {
           Resv6[i] = sa[i];
       }
       for (int i = 0; i < sa.length - idx - 1; i++) {
       Resv6[7 - i] = sa[sa.length - 1 - i];
    } 
  } 
  /* End of Building Result IPv6 address */ 
  s = ""; 
  for (int i = 0; i < 8; i++) { 
     s += Resv6[i]; 
  } 
  
  Finalv6 = new BigInteger(s, 16);
  return Finalv6; 
}; 

These two functions above may also be combined in a general class library to validate and formalize an IPv6 address, but I wrote them in a separate class to keep the functions of the application simple and visible.

As I try to explain in the 'Subnetting with IPv6 Part1/2' article, it is easy and obvious to find the subnet start and end addresses of a given address by using the /prefix-length value. The function StartEndAddresses() below takes an IPv6 address and returns the subnet start and end addresses inside SEaddress object.

Java
public SEaddress StartEndAddresses(SEaddress input) { 
   BigInteger mask = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16);
   mask = mask.shiftRight(input.slash);
   input.End = mask.or(input.Resultv6);
   mask = mask.not();
   input.Start = mask.and(input.Resultv6);

   return input;
}

where SEaddress is a storage object:

Java
public class SEaddress {
    public BigInteger Resultv6 = BigInteger.ZERO;
    public BigInteger Start = BigInteger.ZERO;
    public BigInteger End = BigInteger.ZERO;
    public int slash = 0;
    public int subnetslash = 0;
    public BigInteger subnetidx = BigInteger.ZERO;
}

Another issue is how to find the neighboring or adjacent subnet addresses, or subnets that comes just after our subnet? In other words, how can we move or walk through the adjacent subnet address spaces?

Very easy and simple way of achieving this is to get the end address, and increment by one which gives the start address of the adjacent subnet address. By using this start address, find the end address, then increment by one which will give the second adjacent subnet address, and so on. As you notice, we are now able to move or walk through the subnet address spaces with this algorithm.

An iterative procedure to obtain the adjacent subnet addresses might be:

  • Step 1: Get the IPv6 address
  • Step 2: Find the subnet start address
  • Step 3: Find the subnet end address
  • Step 4: Increment the subnet end address by one. The start address of the next subnet obtained.
  • Step 5: Go to step 3 with the address found in Step 4

For the subnetting, we borrow the bits by using the second slider or track bar. Despite the fact that we can easily find our subnets, now another question is what is the index number of our subnet and how can we find the index number of it? i.e. is it 4th subnet, or 5th, or 6th, or which?

The answer is inside the address itself and we can extract this index number from the address.

Actually, using the second slider, i.e., borrowing the bits, we are creating the subnet index numbers, too.
The interval between the two sliders has our subnet index number. For example, if we drag the first slider to /48 and the second slider to /52, it means that we borrow 4-bits and created 24=16 different subnets having index values from 0 to 15.

So how can we handle finding the index value in our application? We can copy the bits in this interval by means of testing the bits and then setting it into our index variable. For testing the bit, we can perform the bitwise operation (number &(1<< i )), where i is an integer to shift. If the result is greater than zero, then the bit at that position is 1, otherwise it is zero.

The code might be (this little part is also inside the StartEndAddresses() function):

Java
input.subnetidx = BigInteger.ZERO;
   int delta = input.subnetslash - input.slash - 1;
   for (int i = (127 - input.slash); i > (127 - input.subnetslash); i--) {
       if (input.Start.testBit(i) == true) {
                input.subnetidx = input.subnetidx.setBit(delta);
       } 
       else {
                input.subnetidx = input.subnetidx.clearBit(delta);
       }
       delta--;
   }
return input;

Up to this point, we know how to find the subnet start/end addresses and subnet indexes. What is left is to produce these values in a simple for loop with an 'upto' limit variable, e.g.:

Java
for (count = 0; count < upto; count++) {
     subnets = Subnetting(subnets);
       //Display the Results
       //...
     subnets.Start = subnets.End.add(BigInteger.ONE);
}

History

  • 29th September, 2013: v1.0
  • 16th November, 2013: C# v1.1
    • Added new v1.8 C# application
  • 12th December, 2013: C# v1.2
    • A few typing corrections and added v1.10 C# application
  • 26th January, 2014: C# v1.3
    • Added new v1.11 C# application
  • 15th October, 2017: C# v3.6
    • Added new/updated C# application
  • 13th November, 2017: Java v2.0
    • Added new v2.0 Java application based on JavaFX
  • 7th December, 2017: C# v3.7, JavaFX v3.0
    • Added MySQL Database Connection support
      • Store/update/manage IPv6 prefixes with MySQL database server
      • Tested with MySQL-AB JDBC Connector Driver, Ver.5.1.23
      • DriverName: mysql-connector-java-5.1.23-bin.jar
    • Added Statistical View of Assigned/Available Prefixes
      • Note: Assigned prefixes must exist in the database.
    • Added 4-Bytes AS Number plain/dot Conversion Tool
      • Convert Autonomous System Numbers from asplain to asdot and vice versa.
  • 22nd March, 2018: C# v3.8, JavaFX v3.2
    • Added a menu item to manage all opened windows/forms
    • Added a checkbox to display or save the Prefix End-Addresses
  • 7th December, 2018: C# v3.9
    • Added IPv6 Address Type Information
  • 23rd October, 2019: JavaFX v3.3
    • JavaFX MySQL Database Connector Upgraded Version: 8.0.18 (Recommended)
    • DB Prefixes can be queried from the Main/subnetRange/prefixSubLevels forms
    • Used XML file to save the last settings, e.g. DB info.
    • Added a text field showing subnetmask
  • 23rd October, 2019: C# v4.0
    • Target .NET Framework upgraded to 4.7.2
    • MySQL Database Connector Tested Version: 8.0.18 (Recommended)
    • Used XML file to save the last settings, e.g., DB info, language.
    • DB Prefixes can be queried from the Main/subnetRange/prefixSubLevels forms
    • Added a list button to show installed Database Driver Names
    • Added a text field showing subnetmask
  • 6th January, 2020: C# v4.1
    • Target .NET Framework upgraded to 4.8
    • Added IPv4 mode. Both IPv6 and IPv4 settings are saved in XML file.
  • 23rd February, 2020: C# v4.4
    • Minor bug removed from List Reverse DNS.
    • Added SNMA under Compress Tool.
  • 16th April, 2020: C# v4.5
    • Added Service Names and Port Numbers Tool (Data can be updated from IANA).
    • Added Virtual Keyboard.
  • 24th May, 2022: C# v5.0
    • C# database structure changed.
    • MySQL Database Connector Tested Version: 8.0.28 (Recommended)
    • Parent Prefixes are visible.
  • 24th May, 2022: Java v4.0
    • Java codes completely converted to native Java (JavaFX will not be used)
    • MySQL Database connector Tested Version: 8.0.28 (Recommended)
    • Parent Prefixes are visible.

License

This article, along with any associated source code and files, is licensed under The BSD License