4

I read a few of the questions already asked, and i found this to be useful, although i have no tried it Working with IPv6 Addresses in PHP

Still, say i have a 'bans' table in MySQL. How would i go about storing the IPv6 address? The method must be universal, i.e the field must be able to contain either a ipv4 or ipv6 addr. This also must apply to my ip_addr field in my users table.

i would usually check if(getip == $bans['ip']) { do something } But my getip function is for ipv4 afaik and i wonder if it will work.

The function i use is

function getip()
{
    if(isset($_SERVER['REMOTE_ADDR']))
    {
        $ip = $_SERVER['REMOTE_ADDR'];
    }
    elseif(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
    {
    if(preg_match_all("#[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}#s", $_SERVER['HTTP_X_FORWARDED_FOR'], $addresses))
    {
        foreach($addresses[0] as $key => $val)
        {
            if(!preg_match("#^(10|172\.16|192\.168)\.#", $val))
            {
                $ip = $val;
                break;
            }
        }
    }
}

if(!isset($ip))
{
    if(isset($_SERVER['HTTP_CLIENT_IP']))
    {
        $ip = $_SERVER['HTTP_CLIENT_IP'];
    }
    else
    {
        $ip = '';
    }
}

$ip = preg_replace("#([^.0-9 ]*)#", "", $ip);
return $ip;
}
Community
  • 1
  • 1
dikidera
  • 2,004
  • 6
  • 29
  • 36

2 Answers2

9

I was searching for the best data type in mysql to use for storing an ipv6 address recently. I have found no good reason to use a VARCHAR(), only good reasons NOT to.

I did some performance testing with the BINARY(16), two BIGINT UNSIGNED, and DECIMAL data types.

I've created the following tables, populated with 2,000,000 random ip address from 100 random networks.

CREATE TABLE ipv6_address_binary (
    id SERIAL NOT NULL AUTO_INCREMENT PRIMARY KEY,
    addr BINARY(16) NOT NULL UNIQUE
);

CREATE TABLE ipv6_address_twobigints (
    id SERIAL NOT NULL AUTO_INCREMENT PRIMARY KEY,
    haddr BIGINT UNSIGNED NOT NULL,
    laddr BIGINT UNSIGNED NOT NULL,
    UNIQUE uidx (haddr, laddr)
);

CREATE TABLE ipv6_address_decimal (
    id SERIAL NOT NULL AUTO_INCREMENT PRIMARY KEY,
    addr DECIMAL(39,0) NOT NULL UNIQUE
);

Then I SELECT all ip addresses for each network and record the response time. Average response time on the twobigints table is about 1 second while on the binary table it is about one-hundredth of a second.

Here are the queries.

Note:

X_[HIGH/LOW] is the most/least significant 64-bits of X

when NETMASK_LOW is 0 the AND condition is omitted as it always yields true. doesn't affect performance very much.

SELECT COUNT(*) FROM ipv6_address_twobigints
WHERE haddr & NETMASK_HIGH = NETWORK_HIGH
AND laddr & NETMASK_LOW = NETWORK_LOW

SELECT COUNT(*) FROM ipv6_address_binary
WHERE addr >= NETWORK
AND addr <= BROADCAST

SELECT COUNT(*) FROM ipv6_address_decimal
WHERE addr >= NETWORK
AND addr <= BROADCAST

Average response times:

Average response times

BINARY_InnoDB  0.0119529819489
BINARY_MyISAM  0.0139244818687
DECIMAL_InnoDB 0.017379629612
DECIMAL_MyISAM 0.0179929423332
BIGINT_InnoDB  0.782350552082
BIGINT_MyISAM  1.07809265852
Community
  • 1
  • 1
Jake
  • 1,016
  • 8
  • 9
0

Still, say i have a 'bans' table in MySQL. How would i go about storing the IPv6 address?

You can store it in a simple column of VARCHAR(40).
Considering a sample IPv6 max is 40 byte:

2001:0DB8:0000:0000:0000:0000:1428:57ab 

That coulmn will be able to contain IPv4 too

dynamic
  • 46,985
  • 55
  • 154
  • 231
  • You are forgetting that IPv6 addr can be stored in a shorter format. Example: fe80:0000:0000:0000:0202:b3ff:fe1e:8329 could be fe80:0:0:0:202:b3ff:fe1e:8329. Which WILL differ from the record in the DB – dikidera Jun 05 '11 at 12:09
  • @dikidera: why not store it in a canonic way and compare to canonic one? – zerkms Jun 05 '11 at 12:18
  • @dikidera: that's right. at this point before stroign them in mysql just replace :0: with :0000: and you are good. – dynamic Jun 05 '11 at 12:20
  • On the wiki it says, that the short version can also become shorter i.e fe80:0:0:0:202:b3ff:fe1e:8329 can become fe80::202:b3ff:fe1e:8329 so this wont work either. I also need some working functions as this is a first for me. – dikidera Jun 05 '11 at 12:37
  • @diki: that's not hard -.- replace :: with :0000: – dynamic Jun 05 '11 at 12:52
  • I am pretty sure it's not going to be zeroes all the time. – dikidera Jun 05 '11 at 12:57
  • @diki: :: means :0000: all the time – dynamic Jun 05 '11 at 12:58
  • 3
    @yes123: No, it doesn’t. It means “a string of zeroes having the required length”. `::1` (loopback) does _not_ mean `:0000:1`, it means `0000:0000:0000:0000:0000:0000:0000:0001`, while `2001:db8::1428:57ab` means `2001:0db8:0000:0000:0000:0000:1428:57ab`. – Mormegil Aug 23 '11 at 10:04