前文
之前看php socket 部分总觉得是不是php也可以做个dns服务器呢?虽然可以通过该本地的host实现。不过现在host文件由于权限问题,而且只在本地生效,烦。如果可以,那搭个私有dns在局域网也是不错的(国内服务器开53会被警告,不要问我为啥知道)。当然还是有许多工具可以使用,不过后面还是研究起php版本了。最大的好处就是搞定了不就是随便玩么,什么分地区解析啥的不也来试试。
我们搜索php和dns这2个关键字,出来的都是怎么查,很少看到被查。说明这个事没啥人干,那我就更兴奋了。当然这已经是很久前的事情了,看文章创建时间就知道了,今天才来补齐。
源码
写了有些时间了,具体怎么来的忘了。想找个来源发现文档里面没有,可能是根据ReactPHP dns 和udp 部分结合写出来的吧。服了我自己这个老6了。
<?php
/**
* Created by PhpStorm.
* User: lwb
* Date: 2020-4-2
* Time: 21:41
*/
use React\Dns\Model\Message;
use React\Dns\Model\Record;
use React\Dns\Protocol\BinaryDumper;
use React\Dns\Query\CoopExecutor;
use React\Dns\Query\Query;
use React\Dns\Query\TimeoutExecutor;
use React\Dns\Query\UdpTransportExecutor;
require_once __DIR__.'/vendor/autoload.php';
$loop = React\EventLoop\Factory::create();
$factory = new React\Datagram\Factory($loop);
$factory->createServer('0.0.0.0:53')
->then(function (React\Datagram\Socket $server) use ($loop) {
// 非设定的域名转到到8.8.8.8查
$executor = new UdpTransportExecutor('8.8.8.8:53', $loop);
$executor = new CoopExecutor(new TimeoutExecutor($executor, 3.0, $loop));
$server->on('message', function ($message, $address, $server) use ($executor) {
$t = microtime(1);
try {
$ret = (new \React\Dns\Protocol\Parser)->parseMessage($message);
} catch (Exception $exception) {
echo var_export($exception, 1);
return;
}
$name = strtolower($ret->questions[0]->name);
if ($name == 'my.com') {
$response = new Message();
// 返回编号,用于识别
$response->id = $ret->id;
$response->rd = true;
//权威应答
$response->aa = true;
$response->rcode = Message::RCODE_OK;
$response->questions = $ret->questions;
if ($ret->questions[0]->type == Message::TYPE_A ) {
$response->answers[] = new Record($ret->questions[0]->name, Message::TYPE_A, Message::CLASS_IN, 6000, '1.2.3.4');
// 修改为响应标识。
$response->qr = 1;
} else {
$response->qr = 1;
}
$dumper = new BinaryDumper();
$data = $dumper->toBinary($response);
$server->send($data, $address);
} else {
$executor->query(new Query($name, $ret->questions[0]->type, Message::CLASS_IN))
->then(function (Message $message) use ($server, $address, $ret) {
$dumper = new BinaryDumper();
$message->id = $ret->id;
$data = $dumper->toBinary($message);
$server->send($data, $address);
});
}
});
});
$loop->run();
安装
composer require react/dns:^1.9.0
composer require react/datagram:^1.8
运行
php index.php
测试
nslookup my.com 127.0.0.1
结果
# nslookup my.com 127.0.0.1
服务器: UnKnown
Address: 127.0.0.1
名称: my.com
Address: 1.2.3.4
后文
怎么响应有了,后面的就简单了。
至于存解析记录要怎么处理,用reactphp-dns自带的缓存还是reids等,大家随意。
自己简单的处理是写文件里面了,取的时候就去读,然后开个接口用于更新。
关于如何做到分地区解析嘛,后面再分享。