0.1.1
This commit is contained in:
parent
a3a8476bc4
commit
9130d8c2b0
80
Dns.php
80
Dns.php
@ -10,11 +10,27 @@
|
|||||||
namespace Workerman\Protocols;
|
namespace Workerman\Protocols;
|
||||||
class Dns
|
class Dns
|
||||||
{
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
public static function send($response,$query,$info){
|
public static function send($response,$query,$info){
|
||||||
$response=hex2bin($response);
|
$response=hex2bin($response);
|
||||||
$traffic=strlen($response);
|
$traffic=strlen($response);
|
||||||
$info=json_decode($info);
|
$info=json_decode($info);
|
||||||
#var_dump($info);
|
var_dump($info);
|
||||||
#出流量统计
|
#出流量统计
|
||||||
#您也可以在此处保存$response,下一次通过raw类型实现快速缓存相应.
|
#您也可以在此处保存$response,下一次通过raw类型实现快速缓存相应.
|
||||||
return $response;
|
return $response;
|
||||||
@ -426,18 +442,9 @@ class Dns
|
|||||||
$answerRRs=substr($data,12,4);
|
$answerRRs=substr($data,12,4);
|
||||||
$authorityRRs=substr($data,16,4);
|
$authorityRRs=substr($data,16,4);
|
||||||
$additionalRRs=substr($data,20,4);
|
$additionalRRs=substr($data,20,4);
|
||||||
$startbyte=24;
|
$gdomain=Dns::getDomain($data,24);
|
||||||
$dlen=substr($data,$startbyte,2);
|
$realname=$gdomain['name'];
|
||||||
$startbyte=26;
|
$startbyte=$gdomain['startbyte'];
|
||||||
$i=1;
|
|
||||||
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);
|
|
||||||
$type=substr($data,$startbyte,4);
|
$type=substr($data,$startbyte,4);
|
||||||
switch($type){
|
switch($type){
|
||||||
case '0001':
|
case '0001':
|
||||||
@ -466,9 +473,54 @@ class Dns
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$query=substr($data,24,$startbyte-16);
|
$query=substr($data,24,$startbyte-16);
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$returndata= json_encode(array('type' => $type, 'name' => "$realname", 'id'=>"$id", 'query'=>"$query",'traffic'=>$traffic));
|
$returndata= json_encode(array('type' => $type, 'name' => "$realname", 'id'=>"$id", 'query'=>"$query",'traffic'=>$traffic,'addR'=>$addR));
|
||||||
|
|
||||||
return $returndata;
|
return $returndata;
|
||||||
}
|
}
|
||||||
|
48
readme.md
48
readme.md
@ -17,6 +17,7 @@
|
|||||||
- 8182:SERVFAIL≈HTTP503 :服务器错误
|
- 8182:SERVFAIL≈HTTP503 :服务器错误
|
||||||
- 8183:NXDOMAIN≈HTTP404 :记录不存在
|
- 8183:NXDOMAIN≈HTTP404 :记录不存在
|
||||||
- 8185:REFUSE≈HTTP403:拒绝请求
|
- 8185:REFUSE≈HTTP403:拒绝请求
|
||||||
|
- EDNS SubnetIP支持(当通过递归服务器发送请求时,可获取到真实请求服务器的IP段)
|
||||||
|
|
||||||
# 安装
|
# 安装
|
||||||
|
|
||||||
@ -129,7 +130,11 @@ $data=json_decode($data);
|
|||||||
$type=$data->type; #查询类型
|
$type=$data->type; #查询类型
|
||||||
$name=$data->name; #查询内容(一般是域名,PTR时为倒序IP)
|
$name=$data->name; #查询内容(一般是域名,PTR时为倒序IP)
|
||||||
$rip=$connection->getRemoteIp(); #客户端IP
|
$rip=$connection->getRemoteIp(); #客户端IP
|
||||||
|
if(isset($data->addR->csubnet->ip)){
|
||||||
|
$ip=$data->addR->csubnet->ip;
|
||||||
|
}else{
|
||||||
|
$ip=$rip;
|
||||||
|
}
|
||||||
# 请在下方编写您的DNS响应
|
# 请在下方编写您的DNS响应
|
||||||
#——————————————————————
|
#——————————————————————
|
||||||
|
|
||||||
@ -140,7 +145,7 @@ $send['query']=$data->query;
|
|||||||
if(!isset($send['ttl'])){
|
if(!isset($send['ttl'])){
|
||||||
$send['ttl']=0;
|
$send['ttl']=0;
|
||||||
}
|
}
|
||||||
$send['info']=json_encode(['domain'=>$data->name,'querytype'=>$data->type,'answertype'=>$send['type'],'ip'=>$rip,'ttl'=>$send['ttl'],'detail'=>$send['detail']]);
|
$send['info']=json_encode(['domain'=>$data->name,'querytype'=>$data->type,'answertype'=>$send['type'],'ip'=>$ip,'rip'=>$rip,'ttl'=>$send['ttl'],'detail'=>$send['detail']]);
|
||||||
$send=json_encode($send);
|
$send=json_encode($send);
|
||||||
$connection->send($send);
|
$connection->send($send);
|
||||||
};
|
};
|
||||||
@ -159,6 +164,19 @@ Worker::runAll();
|
|||||||
|
|
||||||
# 编写响应:
|
# 编写响应:
|
||||||
|
|
||||||
|
### 响应参数
|
||||||
|
|
||||||
|
您最终需要回复一个$send的数组。定义如下:
|
||||||
|
|
||||||
|
| 名称 | 意义 | 类型 | 示例 | 说明 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| $send['type'] | 响应类型 | 字符串 | $send['type']=A | 指定响应的类型 |
|
||||||
|
| $send['detail'] | 响应内容 | 字符串、数组、多维数组 | 119.29.29.29或$send['detail'][1]='119.29.29.29'或$send['detail']= array(); | 根据不同的响应类型,返回不同的响应。具请往下阅读各种记录的响应方式 |
|
||||||
|
| $send['ttl'] | TTL缓存时间 | 数字 | $send['ttl']=600 | 并非所有记录都需要TTL,未传入时默认0 |
|
||||||
|
| $send['flag'] | Flag类型 | 字符串 | $send['flag']=‘REFUSE’ | 使用flag类型时需指定的flag |
|
||||||
|
| $send['id'] | ID | 数字 | 0001 | 无需更改无需编写。 |
|
||||||
|
| $send['query'] | 请求体 | 16进制 | | 无需更改无需编写。 |
|
||||||
|
| $send['info'] | 请求和响应信息 | json | | 无需编写,基础框架内已经完成。 |
|
||||||
|
|
||||||
您应当根据$name变量,进行响应。
|
您应当根据$name变量,进行响应。
|
||||||
|
|
||||||
@ -465,6 +483,26 @@ object(stdClass)#18 (6) {
|
|||||||
|
|
||||||
其中对于流量将传递$data->traffic变量,其为请求包体的大小(Byte)
|
其中对于流量将传递$data->traffic变量,其为请求包体的大小(Byte)
|
||||||
|
|
||||||
|
# EDNS Subnet IP
|
||||||
|
|
||||||
|
这是一个DNS协议的扩展。支持的递归DNS服务器会向权威DNS发送请求客户端的IP地址。
|
||||||
|
|
||||||
|
WorkermanDNS支持对该协议提供的IPv4进行解析。
|
||||||
|
|
||||||
|
通过我们在上述示例框架start.php中的代码:
|
||||||
|
|
||||||
|
```php
|
||||||
|
if(isset($data->addR->csubnet->ip)){
|
||||||
|
$ip=$data->addR->csubnet->ip;
|
||||||
|
}else{
|
||||||
|
$ip=$rip;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
$ip参数将在支持EDNS SubnetIP的情况下优先使用SubnetIP,不存在时则使用连接到的对端IP。
|
||||||
|
|
||||||
|
对于写入后端记录时,rip与ip 参数都会始终提供。当不支持EDNS SubnetIP时,rip与ip相同。否则,ip是EDNS SubnetIP,rip是udp对端IP。
|
||||||
|
|
||||||
# 运行
|
# 运行
|
||||||
|
|
||||||
使用
|
使用
|
||||||
@ -481,7 +519,11 @@ object(stdClass)#18 (6) {
|
|||||||
|
|
||||||
DNS服务使用53端口,为特权端口,绝大多数情况下必须使用root权限运行。
|
DNS服务使用53端口,为特权端口,绝大多数情况下必须使用root权限运行。
|
||||||
|
|
||||||
### 版本
|
### 版本记录
|
||||||
|
|
||||||
|
[Current]0.1.1@2024/02/06
|
||||||
|
|
||||||
|
添加Edns SubnetIP支持
|
||||||
|
|
||||||
0.1.0@2024/01/31
|
0.1.0@2024/01/31
|
||||||
|
|
||||||
|
@ -20,6 +20,12 @@ $data=json_decode($data);
|
|||||||
$type=$data->type; #查询类型
|
$type=$data->type; #查询类型
|
||||||
$name=$data->name; #查询内容(一般是域名,PTR时为倒序IP)
|
$name=$data->name; #查询内容(一般是域名,PTR时为倒序IP)
|
||||||
$rip=$connection->getRemoteIp(); #客户端IP
|
$rip=$connection->getRemoteIp(); #客户端IP
|
||||||
|
if(isset($data->addR->csubnet->ip)){
|
||||||
|
$ip=$data->addR->csubnet->ip;
|
||||||
|
}else{
|
||||||
|
$ip=$rip;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if($type=='A'){
|
if($type=='A'){
|
||||||
$send['type']='A';
|
$send['type']='A';
|
||||||
@ -198,7 +204,7 @@ $send['query']=$data->query;
|
|||||||
if(!isset($send['ttl'])){
|
if(!isset($send['ttl'])){
|
||||||
$send['ttl']=0;
|
$send['ttl']=0;
|
||||||
}
|
}
|
||||||
$send['info']=json_encode(['domain'=>$data->name,'querytype'=>$data->type,'answertype'=>$send['type'],'ip'=>$rip,'ttl'=>$send['ttl'],'detail'=>$send['detail']]);
|
$send['info']=json_encode(['domain'=>$data->name,'querytype'=>$data->type,'answertype'=>$send['type'],'ip'=>$ip,'rip'=>$rip,'ttl'=>$send['ttl'],'detail'=>$send['detail']]);
|
||||||
|
|
||||||
|
|
||||||
$send=json_encode($send);
|
$send=json_encode($send);
|
||||||
|
53
test.php
53
test.php
@ -1,48 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
$data='a7df00100001000000000001013103646e730457434c4d0264650000010001000029057800008000000b00080007000118007541b3';
|
use Workerman\Worker;
|
||||||
$id=substr($data,0,4);
|
use Workerman\Protocols\Dns;
|
||||||
$flag=substr($data,4,4);
|
require_once __DIR__ . '/php-ipv6.php'; #IPv6支持
|
||||||
$questions=substr($data,8,4);
|
require_once __DIR__ . '/vendor/autoload.php';
|
||||||
$answerRRs=substr($data,12,4);
|
|
||||||
$authorityRRs=substr($data,16,4);
|
echo long2ip(hexdec(substr('7541b3'.'00000000',0,8)));
|
||||||
$additionalRRs=substr($data,20,4);
|
|
||||||
$startbyte=24;
|
|
||||||
$dlen=substr($data,$startbyte,2);
|
|
||||||
$startbyte=26;
|
|
||||||
$i=1;
|
|
||||||
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++;
|
|
||||||
}
|
|
||||||
$name=join(".",$domain);
|
|
||||||
$type=substr($data,$startbyte,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;
|
|
||||||
}
|
|
||||||
$query=substr($data,24,$startbyte-20);
|
|
1365
vendor/workerman/workerman.log
vendored
1365
vendor/workerman/workerman.log
vendored
File diff suppressed because it is too large
Load Diff
82
vendor/workerman/workerman/Protocols/Dns.php
vendored
82
vendor/workerman/workerman/Protocols/Dns.php
vendored
@ -10,11 +10,29 @@
|
|||||||
namespace Workerman\Protocols;
|
namespace Workerman\Protocols;
|
||||||
class Dns
|
class Dns
|
||||||
{
|
{
|
||||||
|
public static function getDomain($data,$startbyte){
|
||||||
|
$dlen=substr($data,$startbyte,2);
|
||||||
|
$startbyte=$startbyte+2;
|
||||||
|
$domain[0]='';
|
||||||
|
$i=0;
|
||||||
|
if($dlen!='00'){
|
||||||
|
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;
|
||||||
|
}
|
||||||
public static function send($response,$query,$info){
|
public static function send($response,$query,$info){
|
||||||
$response=hex2bin($response);
|
$response=hex2bin($response);
|
||||||
$traffic=strlen($response);
|
$traffic=strlen($response);
|
||||||
$info=json_decode($info);
|
$info=json_decode($info);
|
||||||
#var_dump($info);
|
var_dump($info);
|
||||||
#出流量统计
|
#出流量统计
|
||||||
#您也可以在此处保存$response,下一次通过raw类型实现快速缓存相应.
|
#您也可以在此处保存$response,下一次通过raw类型实现快速缓存相应.
|
||||||
return $response;
|
return $response;
|
||||||
@ -426,18 +444,9 @@ class Dns
|
|||||||
$answerRRs=substr($data,12,4);
|
$answerRRs=substr($data,12,4);
|
||||||
$authorityRRs=substr($data,16,4);
|
$authorityRRs=substr($data,16,4);
|
||||||
$additionalRRs=substr($data,20,4);
|
$additionalRRs=substr($data,20,4);
|
||||||
$startbyte=24;
|
$gdomain=Dns::getDomain($data,24);
|
||||||
$dlen=substr($data,$startbyte,2);
|
$realname=$gdomain['name'];
|
||||||
$startbyte=26;
|
$startbyte=$gdomain['startbyte'];
|
||||||
$i=1;
|
|
||||||
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);
|
|
||||||
$type=substr($data,$startbyte,4);
|
$type=substr($data,$startbyte,4);
|
||||||
switch($type){
|
switch($type){
|
||||||
case '0001':
|
case '0001':
|
||||||
@ -466,9 +475,54 @@ class Dns
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$query=substr($data,24,$startbyte-16);
|
$query=substr($data,24,$startbyte-16);
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$returndata= json_encode(array('type' => $type, 'name' => "$realname", 'id'=>"$id", 'query'=>"$query",'traffic'=>$traffic));
|
$returndata= json_encode(array('type' => $type, 'name' => "$realname", 'id'=>"$id", 'query'=>"$query",'traffic'=>$traffic,'addR'=>$addR));
|
||||||
|
|
||||||
return $returndata;
|
return $returndata;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user