Convert IP2Location Decimals to IP

211 views Asked by At

IP ranges in the ip2location database are represented by first and last IPs as integers.

I don't know how the conversion from IPs to integers is done, but documentation indicates it is equivalent to this code in PHP:

function ip62long($ipv6) {
  return (string) gmp_import(inet_pton($ipv6));
}

If it's a IPv4 (not IPv6), the IP is prepended with '::ffff:'.

I'm trying to import ip2location database into postgres using the column type INET. I would want to convert these integers back to IPs, i.e. revert this routine.

So far I'm using this code:

func StringToIp(in string) net.IP {
    var bigint big.Int
    bigint.SetString(in, 10)
    return bigint.Bytes()
}

That works fine for:

  • IPv6 addresses, e.g. 55838750788714571402502155597250560000 -> 2a02:26f7:e5c4:c6c1::

and would work in theory for

  • IPv4 addresses (without the ::ffff: prefix), e.g. 16909060 -> 1.2.3.4

But it does not work for these case:

  • All IPv4 prefixed with ::ffff:, e.g. 281470681743360 should become 0.0.0.0 instead of ?ffff00000000.
  • Cases like 0, 281470681743359, 281474439839744, 281474976710656.

I'm looking for a solution to convert all these values back to IPv4 or IPv6 addresses respectively to store them in postgres and look up IPs later on.

1

There are 1 answers

0
some-user On

The cause of the problem seems to be that bigint.Bytes() returns less than 16 Bytes if the integer doesn't need it, while net.IP expects either 4 or 16 Bytes.

Prepending the []byte up with enough zeros results in proper net.IP:

func StringToIp(in string) net.IP {
    var bigint big.Int
    bigint.SetString(in, 10)
    ip := bigint.Bytes()

    for len(ip) < 16 {
        ip = append([]byte{0x00}, ip...)
    }

    return ip
}

Happy to see and accept other, more elegant, ... solutions.