纯真IP库,珊瑚虫IP库浅析

2023-11-29 09:40
文章标签 ip 浅析 纯真 珊瑚虫

本文主要是介绍纯真IP库,珊瑚虫IP库浅析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

使用PHP操作纯真IP库或珊瑚虫IP库,根据来访者的IP得到所在的物理位置。

我先帖出代码。然后再慢慢一步步浅析出来。希望对想了解这一块的朋友们有帮助。

Only For PHP5的代码。会继续优化代码的。

class IpLocation{
private $fp;
private $wrydat;
private $wrydat_version;
private $ipnumber;
private $firstip;
private $lastip;
private $ip_range_begin;
private $ip_range_end;
private $country;
private $area;
const REDIRECT_MODE_0 = 0;
const REDIRECT_MODE_1 = 1;
const REDIRECT_MODE_2 = 2;
function __construct(){
$args = func_get_args();
$this->wrydat = func_num_args()>0?$args[0]:'CoralWry.dat';
$this->initialize();
}
function __destruct(){
fclose($this->fp);
}
private function initialize(){
if(file_exists($this->wrydat))
$this->fp = fopen($this->wrydat,'rb');
$this->getipnumber();
$this->getwryversion();
}
public function get($str){
return $this->$str;
}
public function set($str,$val){
$this->$str = $val;
}
private function getbyte($length,$offset=null){
if(!is_null($offset)){
fseek($this->fp,$offset,SEEK_SET);
}
$b = fread($this->fp,$length);
return $b;
}
/**
* 把IP地址打包成二进制数据,以big endian(高位在前)格式打包
* 数据存储格式为 little endian(低位在前) 如:
* 00 28 C6 DA 218.198.40.0 little endian
* 3F 28 C6 DA 218.198.40.0 little endian
* 这样的数据无法作二分搜索查找的比较,所以必须先把获得的IP数据使用strrev转换为big endian
* @param $ip
* @return big endian格式的二进制数据
*/
private function packip($ip){
return pack( "N", intval( ip2long( $ip)));
}
private function getlong($length=4, $offset=null){
$chr=null;
for($c=0;$length%4!=0&&$c<(4-$length%4);$c++){
$chr .= chr(0);
}
$var = unpack( "Vlong", $this->getbyte($length, $offset).$chr);
return $var['long'];
}
private function getwryversion(){
$length = preg_match("/coral/i",$this->wrydat)?26:30;
$this->wrydat_version = $this->getbyte($length, $this->firstip-$length);
}
private function getipnumber(){
$this->firstip = $this->getlong();
$this->lastip = $this->getlong();
$this->ipnumber = ($this->lastip-$this->firstip)/7+1;
}
private function getstring($data="",$offset=null){
$char = $this->getbyte(1,$offset);
while(ord($char) > 0){
$data .= $char;
$char = $this->getbyte(1);
}
return $data;
}
private function iplocaltion($ip){
$ip = $this->packip($ip);
$low = 0;
$high = $this->ipnumber-1;
$ipposition = $this->lastip;
while($low <= $high){
$t = floor(($low+$high)/2);
if($ip < strrev($this->getbyte(4,$this->firstip+$t*7))){
$high = $t - 1;
} else {
if($ip > strrev($this->getbyte(4,$this->getlong(3)))){
$low = $t + 1;
}else{
$ipposition = $this->firstip+$t*7;
break;
}
}
}
return $ipposition;
}
private function getarea(){
$b = $this->getbyte(1);
switch(ord($b)){
case self::REDIRECT_MODE_0 :
return "未知";
break;
case self::REDIRECT_MODE_1:
case self::REDIRECT_MODE_2:
return $this->getstring("",$this->getlong(3));
break;
default:
return $this->getstring($b);
break;
}
}
public function getiplocation($ip){
$ippos = $this->iplocaltion($ip);
$this->ip_range_begin = long2ip($this->getlong(4,$ippos));
$this->ip_range_end = long2ip($this->getlong(4,$this->getlong(3)));
$b = $this->getbyte(1);
switch (ord($b)){
case self::REDIRECT_MODE_1:
$b = $this->getbyte(1,$this->getlong(3));
if(ord($b) == REDIRECT_MODE_2){
$countryoffset = $this->getlong(3);
$this->area = $this->getarea();
$this->country = $this->getstring("",$countryoffset);
}else{
$this->country = $this->getstring($b);
$this->area = $this->getarea();
}
break;
case self::REDIRECT_MODE_2:
$countryoffset = $this->getlong(3);
$this->area = $this->getarea();
$this->country = $this->getstring("",$countryoffset);
break;
default:
$this->country = $this->getstring($b);
$this->area = $this->getarea();
break;
}
}
}
/* */
echo microtime();
echo "\n";
$iploca = new IpLocation;
//$iploca = new IpLocation('QQWry.dat');
echo $iploca->get('wrydat_version');
echo "\n";
echo $iploca->get('ipnumber');
echo "\n";
$iploca->getiplocation('211.44.32.34');
/**/
echo $iploca->get('ip_range_begin');
echo "\n";
echo $iploca->get('ip_range_end');
echo "\n";
echo $iploca->get('country');
echo "\n";
echo $iploca->get('area');

echo "\n";
echo $iploca->get('lastip');
echo "\n";
echo microtime();
echo "\n";
unset($iploca);

参考资料:LumaQQ的 纯真IP数据库格式详解

CoralWry.dat文件结构上分为3个区域:

  • 文件头[固定8个字节]
  • 数据区[不固定长度,记录IP的地址信息]
  • 索引区[大小由文件头决定]

该文件数据的存储方式是:little endian。
在这里引用了谈谈Unicode编码里的关于little endian 与 big endian的区别

引用

big endian和little endian是CPU处理多字节数的不同方式。例如“汉”字的Unicode编码是6C49。那么写到文件里时,究竟是将6C写在前面,还是将49写在前 面?如果将6C写在前面,就是big endian。还是将49写在前面,就是little endian。

  “endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。

  我们一般将endian翻译成“字节序”,将big endian和little endian称作“大尾”和“小尾”。

文件头:
红色框框里的就是文件头,前4个字节是索引区的开始地址,后4个字节是索引区的结束地址。

如下图所示:



由于数据库是使用了little endian的字节库,所以我们需要把它倒过来。
把文件头的0-3的字节读取出来,再使用 unpack 函数把二进制数据转换为big endian格式的无符号整型。
处理后,索引区的开始地址位置是:00077450 ;索引区的结束地址位置是:000CE17C。
如果你手头上有UltraEdit的软件,可以打开CoralWry.dat文件,查找地址为:00077450 的位置,那就是IP地址索引区的开始。
如下图所示:



红色框框住那就是索引区的开始位置。

转载于:https://www.cnblogs.com/top5/archive/2009/11/02/1594754.html

这篇关于纯真IP库,珊瑚虫IP库浅析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/432338

相关文章

浅析Rust多线程中如何安全的使用变量

《浅析Rust多线程中如何安全的使用变量》这篇文章主要为大家详细介绍了Rust如何在线程的闭包中安全的使用变量,包括共享变量和修改变量,文中的示例代码讲解详细,有需要的小伙伴可以参考下... 目录1. 向线程传递变量2. 多线程共享变量引用3. 多线程中修改变量4. 总结在Rust语言中,一个既引人入胜又可

shell脚本快速检查192.168.1网段ip是否在用的方法

《shell脚本快速检查192.168.1网段ip是否在用的方法》该Shell脚本通过并发ping命令检查192.168.1网段中哪些IP地址正在使用,脚本定义了网络段、超时时间和并行扫描数量,并使用... 目录脚本:检查 192.168.1 网段 IP 是否在用脚本说明使用方法示例输出优化建议总结检查 1

Redis连接失败:客户端IP不在白名单中的问题分析与解决方案

《Redis连接失败:客户端IP不在白名单中的问题分析与解决方案》在现代分布式系统中,Redis作为一种高性能的内存数据库,被广泛应用于缓存、消息队列、会话存储等场景,然而,在实际使用过程中,我们可能... 目录一、问题背景二、错误分析1. 错误信息解读2. 根本原因三、解决方案1. 将客户端IP添加到Re

SpringBoot实现基于URL和IP的访问频率限制

《SpringBoot实现基于URL和IP的访问频率限制》在现代Web应用中,接口被恶意刷新或暴力请求是一种常见的攻击手段,为了保护系统资源,需要对接口的访问频率进行限制,下面我们就来看看如何使用... 目录1. 引言2. 项目依赖3. 配置 Redis4. 创建拦截器5. 注册拦截器6. 创建控制器8.

Linux限制ip访问的解决方案

《Linux限制ip访问的解决方案》为了修复安全扫描中发现的漏洞,我们需要对某些服务设置访问限制,具体来说,就是要确保只有指定的内部IP地址能够访问这些服务,所以本文给大家介绍了Linux限制ip访问... 目录背景:解决方案:使用Firewalld防火墙规则验证方法深度了解防火墙逻辑应用场景与扩展背景:

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

2024.9.8 TCP/IP协议学习笔记

1.所谓的层就是数据交换的深度,电脑点对点就是单层,物理层,加上集线器还是物理层,加上交换机就变成链路层了,有地址表,路由器就到了第三层网络层,每个端口都有一个mac地址 2.A 给 C 发数据包,怎么知道是否要通过路由器转发呢?答案:子网 3.将源 IP 与目的 IP 分别同这个子网掩码进行与运算****,相等则是在一个子网,不相等就是在不同子网 4.A 如何知道,哪个设备是路由器?答案:在 A

(入门篇)JavaScript 网页设计案例浅析-简单的交互式图片轮播

网页设计已经成为了每个前端开发者的必备技能,而 JavaScript 作为前端三大基础之一,更是为网页赋予了互动性和动态效果。本篇文章将通过一个简单的 JavaScript 案例,带你了解网页设计中的一些常见技巧和技术原理。今天就说一说一个常见的图片轮播效果。相信大家在各类电商网站、个人博客或者展示页面中,都看到过这种轮播图。它的核心功能是展示多张图片,并且用户可以通过点击按钮,左右切换图片。

linux下查看自己的外网ip

局域网的服务器是通过ADSL路由器连接外网的,但ADSL是从ISP运营商那儿通过动态获得IP的,那么我怎么知道自己的外网地址是多少呢? 今天得到几个办法: curl -s http://whatismyip.org wget http://whatismyip.org 然后再  cat index.html 也可以看到

linux下TCP/IP实现简单聊天程序

可以在同一台电脑上运行,在一个终端上运行服务器端,在一个终端上运行客户端。 服务器端的IP地址要和本地的IP相同,并分配端口号,客户端的默认设置为本地,端口号自动分配。 服务器端: #include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <sys/types.