2022-12-16 20:36:45 +08:00
|
|
|
|
<?php
|
|
|
|
|
/**
|
|
|
|
|
* Workerman DNS Protocol
|
|
|
|
|
* @author Enoch EchoNoch Enoch@laysense.com
|
|
|
|
|
* @Repo http://git.laysense.com/enoch/workerman-dns
|
|
|
|
|
* @Github http://github.com/ywnsya/workerman-dns
|
|
|
|
|
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
namespace Workerman\Protocols;
|
|
|
|
|
class Dns
|
|
|
|
|
{
|
2024-02-06 17:49:08 +08:00
|
|
|
|
public static function getDomain($data,$startbyte){
|
|
|
|
|
$dlen=substr($data,$startbyte,2);
|
|
|
|
|
$startbyte=$startbyte+2;
|
|
|
|
|
$domain[0]='';
|
|
|
|
|
$i=0;
|
|
|
|
|
while($dlen!='00'){
|
|
|
|
|
$domain[$i]=hex2bin(substr($data,$startbyte,hexdec($dlen)*2));
|
|
|
|
|
$startbyte=$startbyte+(hexdec($dlen)*2);
|
|
|
|
|
$dlen=substr($data,$startbyte,2);
|
|
|
|
|
$startbyte=$startbyte+2;
|
|
|
|
|
$i++;
|
|
|
|
|
}
|
|
|
|
|
$realname=join(".",$domain);
|
|
|
|
|
$return=['name'=>$realname,'startbyte'=>$startbyte];
|
|
|
|
|
return $return;
|
|
|
|
|
}
|
2024-01-31 01:08:38 +08:00
|
|
|
|
public static function send($response,$query,$info){
|
|
|
|
|
$response=hex2bin($response);
|
|
|
|
|
$traffic=strlen($response);
|
|
|
|
|
$info=json_decode($info);
|
2024-02-06 17:49:08 +08:00
|
|
|
|
var_dump($info);
|
2024-01-31 01:08:38 +08:00
|
|
|
|
#出流量统计
|
|
|
|
|
#您也可以在此处保存$response,下一次通过raw类型实现快速缓存相应.
|
|
|
|
|
return $response;
|
|
|
|
|
}
|
2022-12-16 20:36:45 +08:00
|
|
|
|
/**
|
|
|
|
|
* 检查包的完整性
|
|
|
|
|
* 如果能够得到包长,则返回包的在buffer中的长度,否则返回0继续等待数据
|
|
|
|
|
* 如果协议有问题,则可以返回false,当前客户端连接会因此断开
|
|
|
|
|
* @param string $buffer
|
|
|
|
|
* @return int
|
|
|
|
|
*/
|
|
|
|
|
public static function input($buffer)
|
|
|
|
|
{
|
2024-01-31 01:08:38 +08:00
|
|
|
|
return 512;
|
2022-12-16 20:36:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 打包,当向客户端发送数据的时候会自动调用
|
|
|
|
|
* @param string $buffer
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
public static function encode($buffer)
|
|
|
|
|
{
|
2022-12-18 18:03:25 +08:00
|
|
|
|
|
2022-12-16 20:36:45 +08:00
|
|
|
|
$buffer=json_decode($buffer);
|
|
|
|
|
$type=$buffer->type;
|
|
|
|
|
switch($type){
|
2024-01-31 01:08:38 +08:00
|
|
|
|
case 'raw':
|
|
|
|
|
return Dns::send($buffer->detail,$buffer->query,$buffer->info);
|
|
|
|
|
break;
|
|
|
|
|
case 'flag':
|
|
|
|
|
if($buffer->flag=='NXDOMAIN'){
|
|
|
|
|
$status='8183';
|
|
|
|
|
$questions='0001';
|
|
|
|
|
$AnswerRRs='0000';
|
|
|
|
|
$AuthorityRRs='0001';
|
|
|
|
|
/**
|
|
|
|
|
* NXDOMAIN应当返回SOA记录,主要内容是TTL,LDNS会在SOA的TTL到期前缓存该FLAG,否则会被LDNS递归时拒绝
|
|
|
|
|
*/
|
|
|
|
|
$AdditionalRRs='0000';
|
|
|
|
|
$response=$buffer->id.$status.$questions.$AnswerRRs.$AuthorityRRs.$AdditionalRRs.$buffer->query;
|
|
|
|
|
return Dns::send($response,$buffer->query,$buffer->info);
|
|
|
|
|
}elseif($buffer->flag=='SERVFAIL'){
|
|
|
|
|
$status='8182';
|
|
|
|
|
$questions='0001';
|
|
|
|
|
$AnswerRRs='0000';
|
|
|
|
|
$AuthorityRRs='0000';
|
|
|
|
|
$AdditionalRRs='0000';
|
|
|
|
|
$response=$buffer->id.$status.$questions.$AnswerRRs.$AuthorityRRs.$AdditionalRRs.$buffer->query;
|
|
|
|
|
return Dns::send($response,$buffer->query,$buffer->info);
|
|
|
|
|
}elseif($buffer->flag=='REFUSE'){
|
|
|
|
|
$status='8185';
|
|
|
|
|
$questions='0001';
|
|
|
|
|
$AnswerRRs='0000';
|
|
|
|
|
$AuthorityRRs='0000';
|
|
|
|
|
$AdditionalRRs='0000';
|
|
|
|
|
$response=$buffer->id.$status.$questions.$AnswerRRs.$AuthorityRRs.$AdditionalRRs.$buffer->query;
|
|
|
|
|
return Dns::send($response,$buffer->query,$buffer->info);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2022-12-16 20:36:45 +08:00
|
|
|
|
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;
|
2022-12-18 18:03:25 +08:00
|
|
|
|
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;
|
2024-01-31 01:08:38 +08:00
|
|
|
|
return Dns::send($response,$buffer->query,$buffer->info);
|
2022-12-18 18:03:25 +08:00
|
|
|
|
|
|
|
|
|
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;
|
2024-01-31 01:08:38 +08:00
|
|
|
|
return Dns::send($response,$buffer->query,$buffer->info);
|
2022-12-18 18:03:25 +08:00
|
|
|
|
|
|
|
|
|
break;
|
2022-12-16 20:36:45 +08:00
|
|
|
|
case 'SOA':
|
|
|
|
|
$type='0006';
|
|
|
|
|
$ns=$buffer->detail;
|
|
|
|
|
$ns=json_decode( json_encode( $ns),true);
|
2024-01-31 01:08:38 +08:00
|
|
|
|
if($ns['type']=='auto'){
|
2022-12-16 20:36:45 +08:00
|
|
|
|
$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;
|
2022-12-18 18:03:25 +08:00
|
|
|
|
case 'none':
|
|
|
|
|
$type='0006';
|
|
|
|
|
$ns=$buffer->detail;
|
2024-01-31 01:08:38 +08:00
|
|
|
|
$ns=json_decode( json_encode( $ns),true);
|
|
|
|
|
var_dump($ns);
|
|
|
|
|
|
|
|
|
|
if($ns['type']=='auto'){
|
|
|
|
|
$ns=$ns['name'];
|
|
|
|
|
$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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-12-18 18:03:25 +08:00
|
|
|
|
}else{
|
2024-01-31 01:08:38 +08:00
|
|
|
|
$qname=$ns['qname'];
|
2022-12-18 18:03:25 +08:00
|
|
|
|
}
|
|
|
|
|
$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;
|
2024-01-31 01:08:38 +08:00
|
|
|
|
return Dns::send($response,$buffer->query,$buffer->info);
|
2022-12-18 18:03:25 +08:00
|
|
|
|
break;
|
2022-12-16 20:36:45 +08:00
|
|
|
|
}
|
|
|
|
|
$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;
|
2024-01-31 01:08:38 +08:00
|
|
|
|
$traffic=strlen(hex2bin($response));
|
|
|
|
|
return Dns::send($response,$buffer->query,$buffer->info);
|
2022-12-16 20:36:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 解包,当接收到的数据字节数等于input返回的值(大于0的值)自动调用
|
|
|
|
|
* 并传递给onMessage回调函数的$data参数
|
|
|
|
|
* @param string $buffer
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
public static function decode($buffer)
|
|
|
|
|
{
|
2024-01-31 01:08:38 +08:00
|
|
|
|
$traffic=strlen($buffer);#接收流量
|
|
|
|
|
$data=bin2hex($buffer);
|
|
|
|
|
$id=substr($data,0,4);
|
|
|
|
|
$flag=substr($data,4,4);
|
|
|
|
|
$questions=substr($data,8,4);
|
|
|
|
|
$answerRRs=substr($data,12,4);
|
|
|
|
|
$authorityRRs=substr($data,16,4);
|
|
|
|
|
$additionalRRs=substr($data,20,4);
|
2024-02-06 17:49:08 +08:00
|
|
|
|
$gdomain=Dns::getDomain($data,24);
|
|
|
|
|
$realname=$gdomain['name'];
|
|
|
|
|
$startbyte=$gdomain['startbyte'];
|
2024-01-31 01:08:38 +08:00
|
|
|
|
$type=substr($data,$startbyte,4);
|
2022-12-16 20:36:45 +08:00
|
|
|
|
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;
|
|
|
|
|
}
|
2024-01-31 01:08:38 +08:00
|
|
|
|
$query=substr($data,24,$startbyte-16);
|
2024-02-06 17:49:08 +08:00
|
|
|
|
#additionalRRs
|
|
|
|
|
if($authorityRRs=='0000'&&$additionalRRs=='0001'){
|
|
|
|
|
$addR=new \StdClass();
|
|
|
|
|
$startbyte=$startbyte+8;
|
|
|
|
|
$addR_name=Dns::getDomain($data,$startbyte);
|
|
|
|
|
$addR_rname=$addR_name['name'];
|
|
|
|
|
$startbyte=$addR_name['startbyte'];
|
|
|
|
|
if($addR_rname==''){
|
|
|
|
|
$addR_rname=$realname;
|
|
|
|
|
}
|
|
|
|
|
$addR_type=substr($data,$startbyte,4);
|
|
|
|
|
$startbyte=$startbyte+4;
|
|
|
|
|
$addR->realname=$addR_rname;
|
|
|
|
|
$addR->type=$addR_type;
|
|
|
|
|
#OPT
|
|
|
|
|
if($addR_type=='0029'){
|
|
|
|
|
#dns.rr.udp_playload_size,请求定义该值后响应将可突破512byte默认限制
|
|
|
|
|
$addR->playloadSize=hexdec(substr($data,$startbyte,4));
|
|
|
|
|
$addR->rcode=substr($data,$startbyte+4,2);#dns.resp.ext_rcode
|
|
|
|
|
$addR->edns0v=substr($data,$startbyte+6,2);#Edns0 拓展协议版本
|
|
|
|
|
$addR->Z=substr($data,$startbyte+8,4);
|
|
|
|
|
$addR->optLen=hexdec(substr($data,$startbyte+12,4))*2;
|
|
|
|
|
if($addR->optLen!=0){
|
|
|
|
|
$startbyte=$startbyte+16;
|
|
|
|
|
$opt=substr($data,$startbyte,$addR->optLen);
|
|
|
|
|
$opt_type=substr($opt,0,4);
|
|
|
|
|
if($opt_type=='0008'){
|
|
|
|
|
$addR->opt_type='CSUBNET';
|
|
|
|
|
$csubnet_len=hexdec(substr($opt,4,4))*2;
|
|
|
|
|
$csubnet_data=substr($opt,8,$csubnet_len);
|
|
|
|
|
$csubnet_family=substr($csubnet_data,0,4);
|
|
|
|
|
#IPv4
|
|
|
|
|
if($csubnet_family=='0001'){
|
|
|
|
|
$csubnet_source=substr($csubnet_data,4,2);
|
|
|
|
|
$csubnet_scope=substr($csubnet_data,6,2);
|
|
|
|
|
$csubnet_ip=long2ip(hexdec(substr(substr($csubnet_data,8,$csubnet_len-8).'00000000',0,8)));
|
|
|
|
|
$addR->csubnet=['family'=>$csubnet_family,'source'=>$csubnet_source,'scope'=>$csubnet_scope,'ip'=>$csubnet_ip];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}else{
|
|
|
|
|
$addR=null;
|
|
|
|
|
}
|
2024-01-29 16:39:28 +08:00
|
|
|
|
|
|
|
|
|
|
2024-02-06 17:49:08 +08:00
|
|
|
|
$returndata= json_encode(array('type' => $type, 'name' => "$realname", 'id'=>"$id", 'query'=>"$query",'traffic'=>$traffic,'addR'=>$addR));
|
2022-12-16 20:36:45 +08:00
|
|
|
|
|
|
|
|
|
return $returndata;
|
|
|
|
|
}
|
|
|
|
|
}
|