来自ip2location的IP数据库,并在Perl中将IPV4转换为IPV6

时间:2014-12-10 10:30:10

标签: mysql

我正在尝试从ip2location使用IP到国家/地区数据库。

我的问题是,IPV6数据库文件是否已包含嵌入的IPV4地址 或者我是否必须同时使用IPV4和IPV6数据库来覆盖互联网的所有IP范围 适用于所有版本。

如果我想同时支持IPV4和IPV6,我的意思是我应该加载两个数据库文件 进入相同的mysql表或者我应该只使用IPV6。

我说的是文件IP2LOCATION-LITE-DB11.CSV.ZIP和IP2LOCATION-LITE-DB11.IPV6.CSV.ZIP

1 个答案:

答案 0 :(得分:1)

经过两天的搜索和测试后,我正在回答我自己的问题。 IPV4可以嵌入到IPV6中,此文件IP2LOCATION-LITE-DB11.IPV6.CSV.ZIP包含嵌入为IPV6的IPV4,所有IP都存储为十进制(39,0)。

我在这里使用IPV6数据库文件用于IP的IPV4和IPV6两种版本的技巧是在搜索数据库时将IPV4地址转换为IPV6然后转换为整数并进行正常搜索。这样您的应用程序就支持IPV4和IPV6。

要将IPV4转换为IPV6,这篇wiki文章就是答案:

http://en.wikipedia.org/wiki/IPv6#IPv4-mapped_IPv6_addresses

IPv4映射的IPv6地址

Hybrid dual-stack IPv6/IPv4 implementations recognize a special class of addresses,
the IPv4-mapped IPv6 addresses. In these addresses, the first 80 bits are zero, the 
next 16 bits are one, and the remaining 32 bits are the IPv4 address. One may see these
addresses with the first 96 bits written in the standard IPv6 format, and the 
remaining 32 bits written in the customary dot-decimal notation of IPv4. For example,
::ffff:192.0.2.128 represents the IPv4 address 192.0.2.128. A deprecated format for
IPv4-compatible IPv6 addresses was ::192.0.2.128

并且这篇文章在这个问题上也很好:

IPv6/IPv4 Address Embedding

enter image description here

您需要做的只是在::ffff:前加IP,这样IP地址192.0.2.128::ffff:192.0.2.128作为有效的IPV6。

下一步是将您的IP IPV4或IPV6转换为Decimail(39,0),现在您可以正常搜索数据库。

由于我使用Perl,这里有一些帮助代码进行测试和清除。

use Net::IP ':PROC';

# IPV4 address
my $ipaddress = '197.36.107.146';

my $ip = new Net::IP ($ipaddress) or die (Net::IP::Error());
print ("IPV4  : ".$ip->ip()."\n");
print ("IPV4 Integer : ".$ip->intip()."\n");
print ("Version  : ".$ip->version()."\n");
print ("Size: ".$ip->size()."\n");
print ("Len : ".$ip->prefixlen()."\n");
print ("Type: ".$ip->iptype()."\n");
print "\n";

# Convert IPV4 to IPV6. Just prepend ipv4 with '::ffff:'
my $ip = new Net::IP ("::ffff:".$ipaddress) or die (Net::IP::Error());
print ("IPV6  : ".$ip->ip()."\n");
print ("IPV6 Integer : ".$ip->intip()."\n");
print ("Version  : ".$ip->version()."\n");
print ("Size: ".$ip->size()."\n");
print ("Len : ".$ip->prefixlen()."\n");
print ("Type: ".$ip->iptype()."\n");
print "\n";

# detect the user ip address and convert it

my $user_ip = get_user_ip();
$user_ip ||= $ipaddress; # just for testing on command line
print "Detected User IP address: $user_ip\n";

# if user remote address is IPV4 convert it to IPV6
if ($user_ip =~ /\./) {
    # Convert IPV4 to IPV6
    $user_ip = Net::IP->new("::ffff:$user_ip");
    # Now convert it to Integer
    $user_ip = $user_ip->intip();
}
else {
    # Already IPV6, just convert to Integer
    $user_ip = Net::IP->new($user_ip);
    $user_ip = $user_ip->intip();
}

print "User IP address in IPV6 format: $user_ip\n";
#----------------------------------
# Now you can search the geo database with IPV4 and IPV6 stored as decimails
# select * from ip_country where $ipaddress<=ip_to limit 1
#----------------------------------
sub get_user_ip {
    foreach (qw(REMOTE_ADDR HTTP_CLIENT_IP HTTP_X_FORWARDED_FOR HTTP_X_FORWARDED HTTP_X_CLUSTER_CLIENT_IP
               HTTP_FORWARDED_FOR HTTP_FORWARDED)) {
        if ($ENV{$_}) {
            return $ENV{$_};
        }
    }
}

这是此测试代码的输出:

IPV4  : 197.36.107.146
IPV4 Integer : 3307498386
Version  : 4
Size: 1
Len : 32
Type: PUBLIC

IPV6  : 0000:0000:0000:0000:0000:ffff:c524:6b92
IPV6 Integer : 281473989241746
Version  : 6
Size: 1
Len : 128
Type: IPV4MAP

Detected User IP address: 197.36.107.146
User IP address in IPV6 format: 281473989241746

直到现在搜索数据库显示一切正常。