Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I subtract two IPv6 addresses (128bit numbers) in C/C++?

I'm storing the IP address in sockaddr_in6 which supports an array of four 32-bit, addr[4]. Essentially a 128 bit number.

I'm trying to calculate number of IPs in a given IPv6 range (how many IPs between). So it's a matter of subtracting one from another using two arrays with a length of four.

The problem is since there's no 128bit data type, I can't convert into decimal.

Thanks a ton!

like image 864
shadowyman Avatar asked Aug 12 '15 04:08

shadowyman


1 Answers

You could use some kind of big-int library (if you can tolerate LGPL, GMP is the choice). Fortunately, 128 bit subtraction is easy to simulate by hand if necessary. Here is a quick and dirty demonstration of computing the absolute value of (a-b), for 128 bit values:

#include <iostream>
#include <iomanip>

struct U128
{
    unsigned long long hi;
    unsigned long long lo;
};

bool subtract(U128& a, U128 b)
{
    unsigned long long carry = b.lo > a.lo;
    a.lo -= b.lo;
    unsigned long long carry2 = b.hi > a.hi || a.hi == b.hi && carry;
    a.hi -= carry;
    a.hi -= b.hi;
    return carry2 != 0;
}

int main()
{
    U128 ipAddressA = { 45345, 345345 };
    U128 ipAddressB = { 45345, 345346 };

    bool carry = subtract(ipAddressA, ipAddressB);

    // Carry being set means that we underflowed; that ipAddressB was > ipAddressA.
    // Lets just compute 0 - ipAddressA as a means to calculate the negation 
    // (0-x) of our current value. This gives us the absolute value of the
    // difference.
    if (carry)
    {
        ipAddressB = ipAddressA;
        ipAddressA = { 0, 0 };
        subtract(ipAddressA, ipAddressB);
    }

    // Print gigantic hex string of the 128-bit value
    std::cout.fill ('0');
    std::cout << std::hex << std::setw(16) << ipAddressA.hi << std::setw(16) << ipAddressA.lo << std::endl; 
}

This gives you the absolute value of the difference. If the range is not huge (64 bits or less), then ipAddressA.lo can be your answer as a simple unsigned long long.

If you have perf concerns, you can make use of compiler intrinsics for taking advantage of certain architectures, such as amd64 if you want it to be optimal on that processor. _subborrow_u64 is the amd64 intrinsic for the necessary subtraction work.

like image 186
VoidStar Avatar answered Oct 23 '22 05:10

VoidStar