最新消息:

基于 OpenResty 权威DNS 服务

DNS admin 5438浏览 0评论

NgDNS: https://github.com/selboo/ngdns-server

FROM: https://mp.weixin.qq.com/s/oZ2ftMgPtaDCygrgOUD3QA

最新 Nginx 已经支持 4层服务 ngx_stream_core_module, 有了 4层 支持我们可以做更多服务,

本篇我们用 OpenResty 配合 lua-resty-dns-server 做一个高性能 权威DNS 服务

先来看下压力测试, QPS 10W/s 左右

# cat /tmp/q.txt
lb.sinacloud.com

# queryperf -s 127.0.0.1 -d /tmp/q.txt -l 30
DNS Query Performance Testing Tool
Version: $Id: queryperf.c,v 1.12 2007/09/05 07:36:04 marka Exp $

[Status] Processing input data
[Status] Sending queries (beginning with 10.23.2.241)
[Status] Testing complete

Statistics:

  Parse input file:     multiple times
  Run time limit:       30 seconds
  Ran through file:     3212709 times

  Queries sent:         3212710 queries
  Queries completed:    3212710 queries
  Queries lost:         0 queries
  Queries delayed(?):   0 queries

  RTT max:          0.000836 sec
  RTT min:              0.000069 sec
  RTT average:          0.000153 sec
  RTT std deviation:    0.000030 sec
  RTT out of range:     0 queries

  Percentage completed: 100.00%
  Percentage lost:        0.00%

  Started at:           Wed Jun 19 17:05:33 2019
  Finished at:          Wed Jun 19 17:06:03 2019
  Ran for:              30.000171 seconds

  Queries per second:   107089.722922 qps

 

OpenResty 安装

参考: http://openresty.org/en/installation.html

lua-resty-dns-server 安装

opm install vislee/lua-resty-dns-server

常见DNS类型, 都以支持

nginx.conf 配置

stream {

    server {
        listen 53 udp ;
        content_by_lua_file conf/53.lua;
    }

}

53.lua 代码

local server = require 'resty.dns.server'
local sock, err = ngx.req.socket()
if not sock then
    ngx.log(ngx.ERR, "failed to get the request socket: ", err)
    return ngx.exit(ngx.ERROR)
end

local req, err = sock:receive()
if not req then
    ngx.log(ngx.ERR, "failed to receive: ", err)
    return ngx.exit(ngx.ERROR)
end

local dns = server:new()
local request, err = dns:decode_request(req)
if not request then
    ngx.log(ngx.ERR, "failed to decode request: ", err)

    local resp = dns:encode_response()
    local ok, err = sock:send(resp)
    if not ok then
        ngx.log(ngx.ERR, "failed to send: ", err)
        ngx.exit(ngx.ERROR)
    end

    return
end

local query = request.questions[1]
ngx.log(ngx.DEBUG, "qname: ", query.qname, " qtype: ", query.qtype)

local cname = "sinacloud.com"

if query.qtype == server.TYPE_A then

    local err = dns:create_a_answer(query.qname, 600, "192.168.1.1")
    local err = dns:create_a_answer(query.qname, 600, "192.168.2.2")
    if err then
        ngx.log(ngx.ERR, "failed to create cname answer: ", err)
        return
    end

end

local resp = dns:encode_response()
local ok, err = sock:send(resp)
if not ok then
    ngx.log(ngx.ERR, "failed to send: ", err)
    return
end

dig 测试

 # dig @127.0.0.1 lb.sinacloud.com

; <<>> DiG 9.9.4-RedHat-9.9.4-74.el7_6.1 <<>> @127.0.0.1 lb.sinacloud.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 45924
;; flags: qr rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;lb.sinacloud.com.      IN  A

;; ANSWER SECTION:
lb.sinacloud.com.   600 IN  A   192.168.1.1
lb.sinacloud.com.   600 IN  A   192.168.2.2

;; Query time: 0 msec
;; SERVER: 127.0.0.1#(127.0.0.1)
;; WHEN: Wed Jun 19 17:27:17 CST 2019
;; MSG SIZE  rcvd: 98

后续

目前只是实现了一个很简单的例子,  如果做成一个可持续的服务, 还需要很多工作, 比如:

  • DNS记录可以放到, Redis, MySQL 或这本地文件
  • 封装 API接口, 可以动态修改 DNS记录
  • 从 ngx.var.remote_addr 获取客户端IP, 支持智能解析
  • tld 顶级域 QPS限制
  • 记录请求日志
  • 支持递归查询, 做 LocalDNS 服务
  • 等等…

NgDNS: https://github.com/selboo/ngdns-server

转载请注明:爱开源 » 基于 OpenResty 权威DNS 服务

您必须 登录 才能发表评论!