php实现简单的dns服务

2024-07-05 180 0

前文

之前看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等,大家随意。
自己简单的处理是写文件里面了,取的时候就去读,然后开个接口用于更新。

关于如何做到分地区解析嘛,后面再分享。

    相关文章

    php8中,empty($param[‘time_num’]) 如果这个 time_num 为0 他是真还是假?
    php中使用 Symfony DomCrawler 来获取 HTML 内容中的 token 值
    PHP请求库Guzzle配置代理
    越速云:简单好用的稳定高性价比的云服务器云手机服务商
    php中检查文本内容中是否包某个字符或者名字
    php8中使用正则匹配,不区分大小写的方法

    发布评论