Conversion IPv6 to long and long to IPv6
Asked Answered
D

5

18

How should I perform conversion from IPv6 to long and vice versa?

So far I have:

    public static long IPToLong(String addr) {
            String[] addrArray = addr.split("\\.");
            long num = 0;
            for (int i = 0; i < addrArray.length; i++) {
                    int power = 3 - i;

                    num += ((Integer.parseInt(addrArray[i], 16) % 256 * Math.pow(256, power)));
            }
            return num;
    }

    public static String longToIP(long ip) {
            return ((ip >> 24) & 0xFF) + "."
                    + ((ip >> 16) & 0xFF) + "."
                    + ((ip >> 8) & 0xFF) + "."
                    + (ip & 0xFF);

    }

Is it correct solution or I missed something?

(It would be perfect if the solution worked for both ipv4 and ipv6)

Directive answered 26/7, 2013 at 7:45 Comment(0)
T
12

An IPv6 address is a 128-bit number as described here. A long in Java is represented on 64 bits, so you need another structure, like a BigDecimal or two longs (a container with an array of two longs or simply an array of two longs) in order to store an IPv6 address.

Below is an example (just to provide you an idea):

public class Asd {

    public static long[] IPToLong(String addr) {
        String[] addrArray = addr.split(":");//a IPv6 adress is of form 2607:f0d0:1002:0051:0000:0000:0000:0004
        long[] num = new long[addrArray.length];
        
        for (int i=0; i<addrArray.length; i++) {
            num[i] = Long.parseLong(addrArray[i], 16);
        }
        long long1 = num[0];
        for (int i=1;i<4;i++) {
            long1 = (long1<<16) + num[i];
        }
        long long2 = num[4];
        for (int i=5;i<8;i++) {
            long2 = (long2<<16) + num[i];
        }
        
        long[] longs = {long2, long1};
        return longs;
    }
    
    
    public static String longToIP(long[] ip) {
        String ipString = "";
        for (long crtLong : ip) {//for every long: it should be two of them

            for (int i=0; i<4; i++) {//we display in total 4 parts for every long
                ipString = Long.toHexString(crtLong & 0xFFFF) + ":" + ipString;
                crtLong = crtLong >> 16;
            }
        }
        return ipString;
    
    }
    
    static public void main(String[] args) {
        String ipString = "2607:f0d0:1002:0051:0000:0000:0000:0004";
        long[] asd = IPToLong(ipString);
        
        System.out.println(longToIP(asd));
    }
}
Tungstic answered 26/7, 2013 at 8:20 Comment(9)
Ok, I will do that. What about the conversion? Is it done right?Directive
It is pretty easy to test that: execute longToIP(IPToLong("122.122.122.124")) and you will get "34.34.34.36" instead of the original "122.122.122.124" which means something is not correct.Tungstic
The problem is the following: you tried to adapt the code for IPv4 to IPv6, which is incorrect, because in IPv4 the numbers are encoded in base 10 (the number 124 in the IP address "122.122.122.124" is in base 10), but in IPv6 all parts are encoded in hex. This means, you will have to decide somehow what version the IP address is, and then to make some decisions, in order to have one method for both versions.Tungstic
Thank you for explanation. However I still do not know how to perform the conversion for IPv6. Could you provide a link to some source or an example/tutorial? I couldn't find anything useful.Directive
Added a piece of working code, but do mind that there are missing some checks (like invalid String), so this is ok for your homework, but is not tested enough for production.Tungstic
What about for handling zero suppression and zero collapse?Snug
@Snug is right. This code is missing the zero suppression and zero collapse formatted address strings. Using java.net.InetAddress and java.math.BigInteger takes care of this, see Guigoz's answer.Glandule
Is this portion correct "crtLong & 0xFFFF". Looks fishy, Can we use & operation to find the remainder?Claymore
There is one more issue that it does not handle the overflow.Claymore
V
23

You can also use java.net.InetAddress. It works with both ipv4 and ipv6 (all formats).

The original answer has been updated to use unsigned ints per OTrains's comment.

public static BigInteger ipToBigInteger(String addr) throws UnknownHostException {
    InetAddress a = InetAddress.getByName(addr);
    byte[] bytes = a.getAddress();
    return new BigInteger(1, bytes);
}
Viscountess answered 19/1, 2016 at 15:57 Comment(1)
This will give you negative numbers for the upper half of the IP range. If you want it to be unsigned, you need to pass in the signum to keep it positive valued (ie new BigInteger(1, bytes)).Upolu
T
12

An IPv6 address is a 128-bit number as described here. A long in Java is represented on 64 bits, so you need another structure, like a BigDecimal or two longs (a container with an array of two longs or simply an array of two longs) in order to store an IPv6 address.

Below is an example (just to provide you an idea):

public class Asd {

    public static long[] IPToLong(String addr) {
        String[] addrArray = addr.split(":");//a IPv6 adress is of form 2607:f0d0:1002:0051:0000:0000:0000:0004
        long[] num = new long[addrArray.length];
        
        for (int i=0; i<addrArray.length; i++) {
            num[i] = Long.parseLong(addrArray[i], 16);
        }
        long long1 = num[0];
        for (int i=1;i<4;i++) {
            long1 = (long1<<16) + num[i];
        }
        long long2 = num[4];
        for (int i=5;i<8;i++) {
            long2 = (long2<<16) + num[i];
        }
        
        long[] longs = {long2, long1};
        return longs;
    }
    
    
    public static String longToIP(long[] ip) {
        String ipString = "";
        for (long crtLong : ip) {//for every long: it should be two of them

            for (int i=0; i<4; i++) {//we display in total 4 parts for every long
                ipString = Long.toHexString(crtLong & 0xFFFF) + ":" + ipString;
                crtLong = crtLong >> 16;
            }
        }
        return ipString;
    
    }
    
    static public void main(String[] args) {
        String ipString = "2607:f0d0:1002:0051:0000:0000:0000:0004";
        long[] asd = IPToLong(ipString);
        
        System.out.println(longToIP(asd));
    }
}
Tungstic answered 26/7, 2013 at 8:20 Comment(9)
Ok, I will do that. What about the conversion? Is it done right?Directive
It is pretty easy to test that: execute longToIP(IPToLong("122.122.122.124")) and you will get "34.34.34.36" instead of the original "122.122.122.124" which means something is not correct.Tungstic
The problem is the following: you tried to adapt the code for IPv4 to IPv6, which is incorrect, because in IPv4 the numbers are encoded in base 10 (the number 124 in the IP address "122.122.122.124" is in base 10), but in IPv6 all parts are encoded in hex. This means, you will have to decide somehow what version the IP address is, and then to make some decisions, in order to have one method for both versions.Tungstic
Thank you for explanation. However I still do not know how to perform the conversion for IPv6. Could you provide a link to some source or an example/tutorial? I couldn't find anything useful.Directive
Added a piece of working code, but do mind that there are missing some checks (like invalid String), so this is ok for your homework, but is not tested enough for production.Tungstic
What about for handling zero suppression and zero collapse?Snug
@Snug is right. This code is missing the zero suppression and zero collapse formatted address strings. Using java.net.InetAddress and java.math.BigInteger takes care of this, see Guigoz's answer.Glandule
Is this portion correct "crtLong & 0xFFFF". Looks fishy, Can we use & operation to find the remainder?Claymore
There is one more issue that it does not handle the overflow.Claymore
S
8

An IPv6 address can not be stored in long. You can use BigInteger instead of long.

public static BigInteger ipv6ToNumber(String addr) {
    int startIndex=addr.indexOf("::");

    if(startIndex!=-1){


        String firstStr=addr.substring(0,startIndex);
        String secondStr=addr.substring(startIndex+2, addr.length());


        BigInteger first=ipv6ToNumber(firstStr);

        int x=countChar(addr, ':');

        first=first.shiftLeft(16*(7-x)).add(ipv6ToNumber(secondStr));

        return first;
    }


    String[] strArr = addr.split(":");

    BigInteger retValue = BigInteger.valueOf(0);
    for (int i=0;i<strArr.length;i++) {
        BigInteger bi=new BigInteger(strArr[i], 16);
        retValue = retValue.shiftLeft(16).add(bi);
    }
    return retValue;
}


public static String numberToIPv6(BigInteger ipNumber) {
    String ipString ="";
    BigInteger a=new BigInteger("FFFF", 16);

        for (int i=0; i<8; i++) {
            ipString=ipNumber.and(a).toString(16)+":"+ipString;

            ipNumber = ipNumber.shiftRight(16);
        }

    return ipString.substring(0, ipString.length()-1);

}

public static int countChar(String str, char reg){
    char[] ch=str.toCharArray();
    int count=0;
    for(int i=0; i<ch.length; ++i){
        if(ch[i]==reg){
            if(ch[i+1]==reg){
                ++i;
                continue;
            }
            ++count;
        }
    }
    return count;
}
Sammie answered 8/10, 2013 at 4:15 Comment(0)
D
1

Vinod's answer is right. But there are still some things that can be improved.

First, in method 'countChar', 'continue' should be replaced by 'break'.

And second, Some boundary conditions must be considered.

public static BigInteger ipv6ToNumber(String addr) {
    int startIndex = addr.indexOf("::");
    if (startIndex != -1) {
        String firstStr = addr.substring(0, startIndex);
        String secondStr = addr.substring(startIndex + 2, addr.length());
        BigInteger first = new BigInteger("0");
        BigInteger second = new BigInteger("0");
        if (!firstStr.equals("")) {
            int x = countChar(addr, ':');
            first = ipv6ToNumber(firstStr).shiftLeft(16 * (7 - x));
        }
        if (!secondStr.equals("")) {
            second = ipv6ToNumber(secondStr);
        }
        first = first.add(second);
        return first;
    }

    String[] strArr = addr.split(":");
    BigInteger retValue = BigInteger.valueOf(0);
    for (int i = 0; i < strArr.length; i++) {
        BigInteger bi = new BigInteger(strArr[i], 16);
        retValue = retValue.shiftLeft(16).add(bi);
    }
    return retValue;
}

public static int countChar(String str, char reg){
    char[] ch=str.toCharArray();
    int count=0;
    for(int i=0; i<ch.length; ++i){
        if(ch[i]==reg){
            if(ch[i+1]==reg){
                ++i;
                break;
            }
            ++count;
        }
    }
    return count;
}
Deface answered 28/11, 2018 at 3:10 Comment(0)
M
0

Here's how to do it with the open-source IPAddress Java library. Disclaimer: I am the project manager of that library.

String address = "aaaa:bbbb:cccc:dddd:eeee:ffff:1111:2222";
BigInteger val = new IPAddressString(address).getAddress().getValue();
Mulvihill answered 28/2 at 5:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.