From feef31ca0360a73f27a40e2b803e07debff3eb07 Mon Sep 17 00:00:00 2001 From: Enoch Date: Sun, 18 Dec 2022 18:52:56 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B9=B2=E5=B0=B1=E5=AE=8C=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + composer.json | 13 + image/readme/1671360565549.png | Bin 0 -> 79248 bytes readme.md | 103 +++++ src/Install.php | 80 ++++ src/config/plugin/laysense/dns/app.php | 4 + src/config/plugin/laysense/dns/process.php | 9 + src/install.backup | 78 ++++ src/resource/Dns.php | 419 +++++++++++++++++++++ src/resource/DnsController.php | 33 ++ src/resource/DnsProcess.php | 27 ++ src/resource/ipv6.php | 204 ++++++++++ 12 files changed, 971 insertions(+) create mode 100644 .gitignore create mode 100644 composer.json create mode 100644 image/readme/1671360565549.png create mode 100644 readme.md create mode 100644 src/Install.php create mode 100644 src/config/plugin/laysense/dns/app.php create mode 100644 src/config/plugin/laysense/dns/process.php create mode 100644 src/install.backup create mode 100644 src/resource/Dns.php create mode 100644 src/resource/DnsController.php create mode 100644 src/resource/DnsProcess.php create mode 100644 src/resource/ipv6.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1795c8d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.history \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..4480759 --- /dev/null +++ b/composer.json @@ -0,0 +1,13 @@ +{ + "name": "laysense/dns", + "type": "library", + "license": "MIT", + "description": "Webman plugin laysense/dns. You can making a DNS Server with Webman now", + "require": { + }, + "autoload": { + "psr-4": { + "Laysense\\Dns\\": "src" + } + } +} \ No newline at end of file diff --git a/image/readme/1671360565549.png b/image/readme/1671360565549.png new file mode 100644 index 0000000000000000000000000000000000000000..ac2cc7a4b0c1d74d5a563699e850ba392b6ffe16 GIT binary patch literal 79248 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 注意:默认为udp53端口,需要ROOT权限 + +--- + +## 支持的DNS类型: + +* A +* AAAA +* CNAME +* SOA +* PTR +* MX +* TXT + +最新版本已经增加了CNAME+A和CNAME+AAAA方式 + +--- + +## 安装 + +```shell +composer require laysense/dns +``` + + +## 配置 + +> 配置文件位于 /config/plugin/laysense/dns/process.php + +```php + [ + 'handler' => process\DnsProcess::class, + 'listen' => 'Dns://0.0.0.0:53', #使用的端口,53端口需要root权限 + 'transport' => 'udp', + 'count' => cpu_count() * 4 #线程数量 + ], +]; +``` + + +## 使用 + +> 为了方便您的使用,本插件(不要脸地)导入了一个Controller +> +> 位于 /app/controller/DnsController.php +> +> 【如果这影响到了您的项目和您的开发习惯,请修改/process/DnsProcess.php 文件】 +> +> 安装前请先保障文件不冲突 + +> 本DNS插件只提供了一个DNS请求和响应的接口,其余的数据库、DNS查询、多级缓存、递归等需要您自行实现 + +该Controller名存实亡,其实就是一个class + +```php +ip2bin($ip); + */ + +class DnsController +{ + public function DNS($type,$name,$rip,$id,$query) + { + #输出信息 + #echo "\n Type:$type \n Domain: $name\n Client IP: $rip \n"; + + + #此处请根据业务需要,通过判断$name和$rip返回正确的数据 + #详情请参见 https://github.com/ywnsya/workerman-dns 尤其是 https://github.com/ywnsya/Workerman-DNS/blob/master/start.php 中的用法 + + $send['detail']='dns.laysense.com'; + $send['ttl']=30; + $send['type']='PTR'; + + + #此处无需修改 + $send['id']=$id; + $send['query']=$query; + $return=json_encode($send); + return $return; + } +} +``` + + +具体的使用方式请参照 [Workerman-DNS](https://www.workerman.net/a/1439) ([Github](https://github.com/ywnsya/workerman-dns)) 下的start.php + + +## 赞助(我不要脸) + +![1671360565549](image/readme/1671360565549.png) diff --git a/src/Install.php b/src/Install.php new file mode 100644 index 0000000..1347b4b --- /dev/null +++ b/src/Install.php @@ -0,0 +1,80 @@ + 'config/plugin/laysense/dns', +); + + /** + * Install + * @return void + */ + public static function install() + { + static::installByRelation(); + } + + /** + * Uninstall + * @return void + */ + public static function uninstall() + { + self::uninstallByRelation(); + } + + /** + * installByRelation + * @return void + */ + public static function installByRelation() + { + foreach (static::$pathRelation as $source => $dest) { + if ($pos = strrpos($dest, '/')) { + $parent_dir = base_path().'/'.substr($dest, 0, $pos); + if (!is_dir($parent_dir)) { + mkdir($parent_dir, 0777, true); + } + } + //symlink(__DIR__ . "/$source", base_path()."/$dest"); + copy_dir(__DIR__ . "/$source", base_path()."/$dest"); + echo "Create $dest +"; + } + copy(__DIR__ .'/resource/Dns.php',base_path().'/vendor/workerman/workerman/Protocols/Dns.php'); + echo "Create DNS Protocol Successfully"; + copy(__DIR__ .'/resource/DnsProcess.php',base_path().'/process/DnsProcess.php'); + echo "Create DNS Process Successfully"; + copy(__DIR__ .'/resource/DnsController.php',base_path().'/app/controller/DnsController.php'); + echo "Create Dns Controller Successfully"; + } + + /** + * uninstallByRelation + * @return void + */ + public static function uninstallByRelation() + { + foreach (static::$pathRelation as $source => $dest) { + $path = base_path()."/$dest"; + if (!is_dir($path) && !is_file($path)) { + continue; + } + echo "Remove $dest +"; + if (is_file($path) || is_link($path)) { + unlink($path); + continue; + } + remove_dir($path); + } + } + +} \ No newline at end of file diff --git a/src/config/plugin/laysense/dns/app.php b/src/config/plugin/laysense/dns/app.php new file mode 100644 index 0000000..8f9c426 --- /dev/null +++ b/src/config/plugin/laysense/dns/app.php @@ -0,0 +1,4 @@ + true, +]; \ No newline at end of file diff --git a/src/config/plugin/laysense/dns/process.php b/src/config/plugin/laysense/dns/process.php new file mode 100644 index 0000000..ec5ab5b --- /dev/null +++ b/src/config/plugin/laysense/dns/process.php @@ -0,0 +1,9 @@ + [ + 'handler' => process\DnsProcess::class, + 'listen' => 'Dns://0.0.0.0:53', + 'transport' => 'udp', + 'count' => cpu_count() * 4 + ], +]; \ No newline at end of file diff --git a/src/install.backup b/src/install.backup new file mode 100644 index 0000000..677cc4b --- /dev/null +++ b/src/install.backup @@ -0,0 +1,78 @@ + 'config/plugin/laysense/dns', +); + + /** + * Install + * @return void + */ + public static function install() + { + static::installByRelation(); + } + + /** + * Uninstall + * @return void + */ + public static function uninstall() + { + self::uninstallByRelation(); + } + + /** + * installByRelation + * @return void + */ + public static function installByRelation() + { + foreach (static::$pathRelation as $source => $dest) { + if ($pos = strrpos($dest, '/')) { + $parent_dir = base_path().'/'.substr($dest, 0, $pos); + if (!is_dir($parent_dir)) { + mkdir($parent_dir, 0777, true); + } + } + //symlink(__DIR__ . "/$source", base_path()."/$dest"); + copy_dir(__DIR__ . "/$source", base_path()."/$dest"); + echo "Create $dest +"; + } + copy(__DIR__ .'/resource/Dns.php',base_path().'/vendor/workerman/workerman/Protocols/Dns.php'); + echo "Create DNS Protocol Successfully"; + copy(__DIR__ .'/resource/DnsProcess.php',base_path().'/process/DnsProcess.php'); + echo "Create DNS Process Successfully"; + } + + /** + * uninstallByRelation + * @return void + */ + public static function uninstallByRelation() + { + foreach (static::$pathRelation as $source => $dest) { + $path = base_path()."/$dest"; + if (!is_dir($path) && !is_file($path)) { + continue; + } + echo "Remove $dest +"; + if (is_file($path) || is_link($path)) { + unlink($path); + continue; + } + remove_dir($path); + } + } + +} \ No newline at end of file diff --git a/src/resource/Dns.php b/src/resource/Dns.php new file mode 100644 index 0000000..f44ee5d --- /dev/null +++ b/src/resource/Dns.php @@ -0,0 +1,419 @@ +type; + switch($type){ + case 'A': + $type='0001'; + #$lenth='0004'; + $ip=$buffer->detail; + $n=0; + foreach($ip as $i){ + $nss=explode('.',$i); + $detail[$n]=''; + foreach($nss as $part){ + $tpart=str_pad(dechex($part),2,"0",STR_PAD_LEFT); + $detail[$n]=$detail[$n].$tpart; + }; + $lenth[$n]=str_pad(dechex((strlen($detail[$n])/2)),4,"0",STR_PAD_LEFT); + $n=$n+1; + }; + break; + case 'NS': + $type='0002'; + #$lenth='0004'; + $ns=$buffer->detail; + $n=0; + foreach($ns as $i){ + $nss=explode('.',$i); + $detail[$n]=''; + foreach($nss as $part){ + #$len=strlen($part); + $len=str_pad(dechex(strlen($part)),2,"0",STR_PAD_LEFT); + $tpart=bin2hex($part); + $detail[$n]=$detail[$n].$len.$tpart; + }; + $detail[$n]=$detail[$n].'00'; + $lenth[$n]=str_pad(dechex((strlen($detail[$n])/2)),4,"0",STR_PAD_LEFT); + $n=$n+1; + }; + break; + case 'PTR': + $type='000C'; + $ns=$buffer->detail; + $nss=explode('.',$ns); + $detail[0]=''; + foreach($nss as $part){ + $len=str_pad(dechex(strlen($part)),2,"0",STR_PAD_LEFT); + $tpart=bin2hex($part); + $detail[0]=$detail[0].$len.$tpart; + }; + $detail[0]=$detail[0].'00'; + $lenth[0]=str_pad(dechex((strlen($detail[0])/2)),4,"0",STR_PAD_LEFT); + break; + case 'CNAME': + $type='0005'; + $ns=$buffer->detail; + $n=0; + foreach($ns as $i){ + $nss=explode('.',$i); + $detail[$n]=''; + foreach($nss as $part){ + #$len=strlen($part); + $len=str_pad(dechex(strlen($part)),2,"0",STR_PAD_LEFT); + $tpart=bin2hex($part); + $detail[$n]=$detail[$n].$len.$tpart; + }; + $detail[$n]=$detail[$n].'00'; + $lenth[$n]=str_pad(dechex((strlen($detail[$n])/2)),4,"0",STR_PAD_LEFT); + $n=$n+1; + }; + break; + case 'CNAME+A': + $type='0005'; + $ns=$buffer->detail; + $nss=explode('.',$ns); + $detail[0]=''; + foreach($nss as $part){ + $len=str_pad(dechex(strlen($part)),2,"0",STR_PAD_LEFT); + $tpart=bin2hex($part); + $detail[0]=$detail[0].$len.$tpart; + }; + $detail[0]=$detail[0].'00'; + $lenth[0]=str_pad(dechex((strlen($detail[0])/2)),4,"0",STR_PAD_LEFT); + + $ttl=str_pad(dechex($buffer->ttl),8,"0",STR_PAD_LEFT); + + $answer=''; + $answer=$answer.'C00C'.$type.'0001'.$ttl.$lenth[0].$detail[0]; + + $ip=dns_get_record($ns,DNS_A); + $type='0001'; + $n=0; + foreach($ip as $i){ + $ttl=str_pad(dechex($i['ttl']),8,"0",STR_PAD_LEFT); + $i=$i['ip']; + $nss=explode('.',$i); + $detail[$n]=''; + foreach($nss as $part){ + $tpart=str_pad(dechex($part),2,"0",STR_PAD_LEFT); + $detail[$n]=$detail[$n].$tpart; + }; + $lenth[$n]=str_pad(dechex((strlen($detail[$n])/2)),4,"0",STR_PAD_LEFT); + $n=$n+1; + + }; + $n=0; + foreach($detail as $c){ + $rlenth=''; + $rlenth=$lenth[$n]; + $n=$n+1; + $answer=$answer.'C02B'.$type.'0001'.$ttl.$rlenth.$c; + } + + $status='8180'; + $questions='0001'; + $AuthorityRRs='0000'; + $AdditionalRRs='0000'; + + $AnswerRRs=str_pad((count((array)$ip)+1),4,"0",STR_PAD_LEFT); + + $response=$buffer->id.$status.$questions.$AnswerRRs.$AuthorityRRs.$AdditionalRRs.$buffer->query.$answer; + return hex2bin($response); + + break; + case 'CNAME+AAAA': + $type='0005'; + $ns=$buffer->detail; + $nss=explode('.',$ns); + $detail[0]=''; + foreach($nss as $part){ + $len=str_pad(dechex(strlen($part)),2,"0",STR_PAD_LEFT); + $tpart=bin2hex($part); + $detail[0]=$detail[0].$len.$tpart; + }; + $detail[0]=$detail[0].'00'; + $lenth[0]=str_pad(dechex((strlen($detail[0])/2)),4,"0",STR_PAD_LEFT); + + $ttl=str_pad(dechex($buffer->ttl),8,"0",STR_PAD_LEFT); + + $answer=''; + $answer=$answer.'C00C'.$type.'0001'.$ttl.$lenth[0].$detail[0]; + + $ip=dns_get_record($ns,DNS_AAAA); + $type='001C'; + $n=0; + foreach($ip as $i){ + $ipv6=$i['ipv6']; + $hexstr = unpack("H*hex", inet_pton($ipv6)); + $ipv6=substr(preg_replace("/([A-f0-9]{4})/", "$1:", $hexstr['hex']), 0, -1); + $ipv6=str_replace(':','',$ipv6); + #$ipv6= bin2hex($ipv6); + $detail[$n]="$ipv6"; + $lenth[$n]="0010"; + $n=$n+1; + }; + + $n=0; + foreach($detail as $c){ + $rlenth=''; + $rlenth=$lenth[$n]; + $n=$n+1; + $answer=$answer.'C02C'.$type.'0001'.$ttl.$rlenth.$c; + } + + $status='8180'; + $questions='0001'; + $AuthorityRRs='0000'; + $AdditionalRRs='0000'; + + $AnswerRRs=str_pad((count((array)$ip)+1),4,"0",STR_PAD_LEFT); + + $response=$buffer->id.$status.$questions.$AnswerRRs.$AuthorityRRs.$AdditionalRRs.$buffer->query.$answer; + return hex2bin($response); + + break; + case 'SOA': + $type='0006'; + $ns=$buffer->detail; + $ns=json_decode( json_encode( $ns),true); + if($ns['type']=='none'){ + $Rns=dns_get_record($ns['name'],DNS_SOA); + $Rns=$Rns[0]; + $ns=$Rns; + $buffer->ttl=$Rns['ttl']; + } + + $nss=explode('.',$ns['mname']); + $detail[0]=''; + foreach($nss as $part){ + $len=str_pad(dechex(strlen($part)),2,"0",STR_PAD_LEFT); + $tpart=bin2hex($part); + $detail[0]=$detail[0].$len.$tpart; + }; + $detail[0]=$detail[0].'00'; + unset($nss,$len,$tpart); + $nss=explode('.',$ns['rname']); + foreach($nss as $part){ + $len=str_pad(dechex(strlen($part)),2,"0",STR_PAD_LEFT); + $tpart=bin2hex($part); + $detail[0]=$detail[0].$len.$tpart; + }; + $detail[0]=$detail[0].'00'.str_pad(dechex($ns['serial']),8,"0",STR_PAD_LEFT).str_pad(dechex($ns['refresh']),8,"0",STR_PAD_LEFT).str_pad(dechex($ns['retry']),8,"0",STR_PAD_LEFT).str_pad(dechex($ns['expire']),8,"0",STR_PAD_LEFT).str_pad(dechex($ns['minimum-ttl']),8,"0",STR_PAD_LEFT); + + + $lenth[0]=str_pad(dechex((strlen($detail[0])/2)),4,"0",STR_PAD_LEFT); + break; + case 'AAAA': + $type='001C'; + $ip=$buffer->detail; + $n=0; + foreach($ip as $i){ + $detail[$n]="$i"; + $lenth[$n]="0010"; + $n=$n+1; + }; + break; + case 'TEXT': + $type='0010'; + $ns=$buffer->detail; + $n=0; + foreach($ns as $i){ + $detail[$n]=''; + $text=bin2hex($i); + $tlen=str_pad(dechex((strlen($text)/2)),2,"0",STR_PAD_LEFT); + $detail[$n]=$tlen.$text; + $lenth[$n]=str_pad(dechex((strlen($detail[$n])/2)),4,"0",STR_PAD_LEFT); + $n=$n+1; + }; + break; + case 'MX': + $type='000F'; + $ns=$buffer->detail; + $n=0; + + print_r($ns); + + foreach($ns as $i){ + $nss=explode('.',$i->name); + $detail[$n]=''; + foreach($nss as $part){ + #$len=strlen($part); + $len=str_pad(dechex(strlen($part)),2,"0",STR_PAD_LEFT); + $tpart=bin2hex($part); + $detail[$n]=$detail[$n].$len.$tpart; + }; + $detail[$n]=$detail[$n].'00'; + $lenth[$n]=str_pad(dechex((strlen($detail[$n])/2)+2),4,"0",STR_PAD_LEFT).str_pad(dechex($i->pre),4,"0",STR_PAD_LEFT); + $n=$n+1; + }; + break; + case 'none': + $type='0006'; + $ns=$buffer->detail; + $url=$ns; + while(true){ + preg_match("#\.(.*)#i",$url,$match);//获取根域名 + $domin = $match[1]; + $soa=dns_get_record($domin,DNS_SOA); + if(array_key_exists('0',$soa)){ + if(array_key_exists('mname',$soa[0])){ + $qname=$domin; + $ns=$soa[0]; + break; + }else{ + $url=$domin; + } + }else{ + $url=$domin; + } + } + + $nss=explode('.',$ns['mname']); + $detail=''; + foreach($nss as $part){ + $len=str_pad(dechex(strlen($part)),2,"0",STR_PAD_LEFT); + $tpart=bin2hex($part); + $detail=$detail.$len.$tpart; + }; + $detail=$detail.'00'; + unset($nss,$len,$tpart); + $nss=explode('.',$ns['rname']); + foreach($nss as $part){ + $len=str_pad(dechex(strlen($part)),2,"0",STR_PAD_LEFT); + $tpart=bin2hex($part); + $detail=$detail.$len.$tpart; + }; + $detail=$detail.'00'.str_pad(dechex($ns['serial']),8,"0",STR_PAD_LEFT).str_pad(dechex($ns['refresh']),8,"0",STR_PAD_LEFT).str_pad(dechex($ns['retry']),8,"0",STR_PAD_LEFT).str_pad(dechex($ns['expire']),8,"0",STR_PAD_LEFT).str_pad(dechex($ns['minimum-ttl']),8,"0",STR_PAD_LEFT); + + + $lenth=str_pad(dechex((strlen($detail)/2)),4,"0",STR_PAD_LEFT); + $ttl=str_pad(dechex($buffer->ttl),8,"0",STR_PAD_LEFT); + $status='8183'; + $questions='0001'; + $AnswerRRs='0000'; + $AuthorityRRs='0001'; + $AdditionalRRs='0000'; + + #$qname + $nss=explode('.',$qname); + $qname=''; + foreach($nss as $part){ + #$len=strlen($part); + $len=str_pad(dechex(strlen($part)),2,"0",STR_PAD_LEFT); + $tpart=bin2hex($part); + $qname=$qname.$len.$tpart; + }; + $qname=$qname.'00'; + + $answer=''; + $answer=$answer.$qname.$type.'0001'.$ttl.$lenth.$detail; + $response=$buffer->id.$status.$questions.$AnswerRRs.$AuthorityRRs.$AdditionalRRs.$buffer->query.$answer; + return hex2bin($response); + break; + } + $ttl=str_pad(dechex($buffer->ttl),8,"0",STR_PAD_LEFT); + $status='8180'; + $questions='0001'; + $AnswerRRs=str_pad(count((array)$buffer->detail),4,"0",STR_PAD_LEFT); + $AuthorityRRs='0000'; + $AdditionalRRs='0000'; + $answer=''; + $n=0; + foreach($detail as $c){ + $rlenth=''; + $rlenth=$lenth[$n]; + $n=$n+1; + $answer=$answer.'C00C'.$type.'0001'.$ttl.$rlenth.$c; + } + $response=$buffer->id.$status.$questions.$AnswerRRs.$AuthorityRRs.$AdditionalRRs.$buffer->query.$answer; + return hex2bin($response); + } + + /** + * 解包,当接收到的数据字节数等于input返回的值(大于0的值)自动调用 + * 并传递给onMessage回调函数的$data参数 + * @param string $buffer + * @return string + */ + public static function decode($buffer) + { + $data=bin2hex($buffer); + $id=substr($data,0,4); + $type=substr($data,-8,4); + switch($type){ + case '0001': + $type='A'; + break; + case '0002': + $type='NS'; + break; + case '000c': + $type='PTR'; + break; + case '0006': + $type='SOA'; + break; + case '001c': + $type='AAAA'; + break; + case '0005': + $type='CNAME'; + break; + case '0010': + $type='TEXT'; + break; + case '000f': + $type='MX'; + break; + } + $name=substr($data,24,-8); + $namede=str_split($name,2); + $realname=''; + foreach($namede as $cha){ + $chat=hex2bin($cha); + if(!ctype_alnum($chat)){ + $chat='.'; + } + $realname=$realname.$chat; + } + $realname=substr($realname,1,-1); + $query=substr($data,24); + + #$returndata="$type".'|||'."$realname"; + $returndata= json_encode(array('type' => $type, 'name' => "$realname", 'id'=>"$id", 'query'=>"$query")); + + return $returndata; + } +} \ No newline at end of file diff --git a/src/resource/DnsController.php b/src/resource/DnsController.php new file mode 100644 index 0000000..8c3d2af --- /dev/null +++ b/src/resource/DnsController.php @@ -0,0 +1,33 @@ +ip2bin($ip); + */ + +class DnsController +{ + public function DNS($type,$name,$rip,$id,$query) + { + #输出信息 + #echo "\n Type:$type \n Domain: $name\n Client IP: $rip \n"; + + + #此处请根据业务需要,通过判断$name和$rip返回正确的数据 + #详情请参见 https://github.com/ywnsya/workerman-dns 尤其是 https://github.com/ywnsya/Workerman-DNS/blob/master/start.php 中的用法 + + $send['detail']='dns.laysense.com'; + $send['ttl']=30; + $send['type']='PTR'; + + + #此处无需修改 + $send['id']=$id; + $send['query']=$query; + $return=json_encode($send); + return $return; + } +} \ No newline at end of file diff --git a/src/resource/DnsProcess.php b/src/resource/DnsProcess.php new file mode 100644 index 0000000..dbfe9b4 --- /dev/null +++ b/src/resource/DnsProcess.php @@ -0,0 +1,27 @@ +send($data); + } + + public function onClose(TcpConnection $connection) + { + echo "onClose\n"; + } +} \ No newline at end of file diff --git a/src/resource/ipv6.php b/src/resource/ipv6.php new file mode 100644 index 0000000..d686a34 --- /dev/null +++ b/src/resource/ipv6.php @@ -0,0 +1,204 @@ + + */ +class ipv6 { + function addr($addr=null) { + // 常规获取IPv6地址或格式化IP地址为IPv6格式 + !$addr && ($addr = $_SERVER['REMOTE_ADDR']); + $type = self::type($addr); + if ( $type === 6 && self::ipv6_check($addr) ) return $addr; + elseif ( $type === 4 ) return self::ip426($addr); + else return 'Unknown'; + } + + /** + * realip()因为在Webman(Workerman)下无效,为防止冲突已删除 + */ + + function cut($addr) { + // 压缩IPv6地址 + if (!self::ipv6_check($addr)) return $addr; + $addr = self::fill($addr); + $arr = explode(':',$addr); + foreach ($arr as $a) { + $arr2[] = preg_replace('/^0{1,3}(\w+)/','\1',$a); + } + $addr = join(':',$arr2); + $olen = strlen($addr); + for($i=6;$i>0;$i--){ + // 初步压缩 + $addr = preg_replace('/:(0\:){'.$i.'}/','::',$addr,1); + if (strlen($addr) < $olen ) break; + } + $addr = preg_replace('/^0\:\:/','::',$addr); + $addr = preg_replace('/\:\:0$/','::',$addr); + return $addr; + } + + function fill($addr) { + // 标准IPv6格式 + if (!self::ipv6_check($addr)) return $addr; + $addr = self::_fix_v4($addr); + $arr = explode(':',$addr); + foreach ($arr as $a) { + $l = strlen($a); + if ( $l > 0 && $l < 4 ) + $arr2[] = str_repeat('0', 4-$l).$a; + else $arr2[] = $a; + } + $addr = join(':',$arr2); + $fil = ':'.str_repeat('0000:', 9-count($arr)); + $addr = str_replace('::',$fil,$addr); + $addr = preg_replace('/^\:/','0000:',$addr); + $addr = preg_replace('/\:$/',':0000',$addr); + return $addr; + } + + function ip2bin($addr) { + $type = self::type($addr); + if ( $type === 0 ) return false; + elseif ( $type === 4 ) $addr = self::ip426($addr); + else $addr = self::fill($addr); + $hexstr = str_replace(':','',$addr); + return pack('H*', $hexstr); + } + + function bin2ip($bin) { + if ( strlen($bin) !== 16 ) return false; + $arr = str_split(join('',unpack('H*', $bin)), 4); + $addr = join(':',$arr); + return $addr; + } + + function ip426($addr) { + // IPv4 to IPv6 + if (!self::ipv4_check($addr)) return $addr; + $hex = dechex(self::ip2long($addr)); + $hex = str_repeat('0', 8-strlen($hex)).$hex; + $ipv6 = '0000:0000:0000:0000:0000:0000:'; + $ipv6 .= substr($hex,0,4) . ':' . substr($hex,4,4); + return $ipv6; + } + + function type($addr) { + if ( self::ipv6_check($addr) ) return 6; + elseif ( self::ipv4_check($addr) ) return 4; + else return 0; + } + + function ipv4_check($addr) { + $arr = explode('.', $addr); + $l = count($arr); + for ( $i=0;$i<$l;$i++ ) { + if ( strlen($arr[$i]) > 3 ) return false; + if ( !is_numeric($arr[$i]) ) return false; + $a = intval($arr[$i], 10); + if ($a > 255 || $a <0) return false; + } + return true; + } + + function ipv6_check($addr) { + $addr = self::_fix_v4($addr); + if ( strpos($addr, '.') ) return false; + $l1 = count(explode('::',$addr)); + if ( $l1 > 2 ) return false; + $l2 = count(explode(':',$addr)); + if ( $l2 < 3 || $l2 > 8 ) return false; + if ( $l2 < 8 && $l1 !== 2 ) return false; + preg_match('/^([0-9a-f]{0,4}\:)+[0-9a-f]{0,4}$/i',$addr,$arr); + if ( !$arr[0] ) return false; + return true; + } + + function ip2long($addr) { + $arr = explode('.', $addr); + $l = count($arr); + $long = 0; + for ( $i=0;$i<$l;$i++ ) { + if ( strlen($arr[$i]) > 3 ) return false; + if ( !is_numeric($arr[$i]) ) return false; + $a = intval($arr[$i], 10); + if ($a > 255 || $a <0) return false; + $long += $a * pow(2, 24-$i*8); + } + return $long; + } + + function wan_ip($addr) { + // 检查外网可用地址 + if ( self::ipv6_check($addr) ) { + $addr = self::fill($addr); + // IPv4类地址处理 + $v4p = substr($addr,0,29); + if ( $v4p == '0000:0000:0000:0000:0000:0000' + || strtolower($v4p) == 'ffff:0000:0000:0000:0000:0000' ) { + $t = str_replace($v4p,'',$addr); + $t = str_replace(':','',$t); + $ipv4 = long2ip(hexdec($t)); + return self::_wan_ipv4($ipv4); + } + // 取前16位进行比较 + $v6p = substr($addr,0,4); + $bin = decbin(hexdec($v6p)); + $p = str_repeat(0, 16-strlen($bin)).$bin; + if ( (($p&'1110000000000000')=='0010000000000000') //2000::/3 + || (($p&'1111111000000000')=='1111110000000000') //FC00::/7 + || (($p&'1111111111000000')=='1111111010000000') //FE80::/10 + || (($p&'1111111100000000')=='1111111100000000') //FF00::/8 + ) return false; + return true; + } else { + return self::_wan_ipv4($addr); + } + } + + private function _wan_ipv4($addr){ + if ( !self::ipv4_check($addr) ) return false; + $arr = explode('.',$addr); + $bin = decbin($arr[0]*256+$arr[1]); + $p = str_repeat(0, 16-strlen($bin)).$bin; + $p8 = $p & '1111111100000000'; + $p16 = &$p; + if ( ($p8 == '0000000000000000') // 0/8 + || ($p8 == '0000010100000000') // 5/8 + || ($p8 == '0000101000000000') // 10/8 + || ($p8 == '0001011100000000') // 23/8 + || ($p8 == '0010010000000000') // 36/8 + || ($p8 == '0010010100000000') // 37/8 + || ($p8 == '0010011100000000') // 39/8 + || ($p8 == '0010101000000000') // 42/8 + || ($p8 == '0110010000000000') // 100/8 + || ($p8 == '0110011000000000') // 102/8 + || ($p8 == '0110011100000000') // 103/8 + || ($p8 == '0110100000000000') // 104/8 + || ($p8 == '0110100100000000') // 105/8 + || ($p8 == '0110101000000000') // 106/8 + || ($p8 == '0111111100000000') // 127/8 + || ($p16 == '1010100111111110') // 169.254/16 + || (($p&'1111111111110000')=='1010110000010000') // 172.16/12 + || ($p8 == '1011001100000000') // 179/8 + || ($p8 == '1011100100000000') // 185/8 + || ($p16 == '1100000010101000') // 192.168/16 + || (($p&'1110000000000000')=='1110000000000000') // 224/8-255/8 + ) return false; + return true; + } + + private function _fix_v4($addr) { + // 修正IPv4位址类IPv6格式为标准IPv6格式,不验证合法性 + if ( !strpos($addr, '.') ) return $addr; + preg_match('/(\d+\.){3}\d+$/',$addr,$arr); + if ( !self::ipv4_check($arr[0]) ) return $addr; + $hex = dechex(self::ip2long($arr[0])); + $hex = str_repeat('0', 8-strlen($hex)).$hex; + $v4p = substr($hex,0,4) . ':' . substr($hex,4,4); + $p1 = str_replace($arr[0],'',$addr); + strtolower($p1) === 'ffff:' && $p1 = '::'.$p1; + $addr = $p1 . $v4p; + return $addr; + } +} +?> \ No newline at end of file