dns-server: Driver de servidor DNS Lua para nginx-module-lua
Instalação
Se você ainda não configurou a assinatura do repositório RPM, inscreva-se. Em seguida, você pode prosseguir com os seguintes passos.
CentOS/RHEL 7 ou Amazon Linux 2
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install lua-resty-dns-server
CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-dns-server
Para usar esta biblioteca Lua com NGINX, certifique-se de que o nginx-module-lua esteja instalado.
Este documento descreve o lua-resty-dns-server v0.2 lançado em 23 de julho de 2019.
Esta biblioteca Lua fornece um driver de servidor DNS para o módulo ngx_lua do NGINX:
https://github.com/openresty/stream-lua-nginx-module/#readme
Sinopse
stream {
server {
listen 53 udp;
content_by_lua_block {
local server = require 'resty.dns.server'
local sock, err = ngx.req.socket()
if not sock then
ngx.log(ngx.ERR, "falha ao obter o socket da requisição: ", err)
return ngx.exit(ngx.ERROR)
end
local req, err = sock:receive()
if not req then
ngx.log(ngx.ERR, "falha ao receber: ", 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, "falha ao decodificar a requisição: ", err)
local resp = dns:encode_response()
local ok, err = sock:send(resp)
if not ok then
ngx.log(ngx.ERR, "falha ao enviar: ", err)
ngx.exit(ngx.ERROR)
end
return
end
local query = request.questions[1]
ngx.log(ngx.DEBUG, "qname: ", query.qname, " qtype: ", query.qtype)
local subnet = request.subnet[1]
if subnet then
ngx.log(ngx.DEBUG, "endereço da subnet: ", subnet.address, " máscara: ", subnet.mask, " família: ", subnet.family)
end
local cname = "sinacloud.com"
if query.qtype == server.TYPE_CNAME or
query.qtype == server.TYPE_AAAA or query.qtype == server.TYPE_A then
local err = dns:create_cname_answer(query.qname, 600, cname)
if err then
ngx.log(ngx.ERR, "falha ao criar resposta cname: ", err)
return
end
else
dns:create_soa_answer("test.com", 600, "a.root-test.com", "vislee.test.com", 1515161223, 1800, 900, 604800, 86400)
end
local resp = dns:encode_response()
local ok, err = sock:send(resp)
if not ok then
ngx.log(ngx.ERR, "falha ao enviar: ", err)
return
end
}
}
server {
listen 53;
content_by_lua_block {
local bit = require 'bit'
local lshift = bit.lshift
local rshift = bit.rshift
local band = bit.band
local byte = string.byte
local char = string.char
local server = require 'resty.dns.server'
local sock, err = ngx.req.socket()
if not sock then
ngx.log(ngx.ERR, "falha ao obter o socket da requisição: ", err)
return ngx.exit(ngx.ERROR)
end
local buf, err = sock:receive(2)
if not buf then
ngx.log(ngx.ERR, "falha ao receber: ", err)
return ngx.exit(ngx.ERROR)
end
local len_hi = byte(buf, 1)
local len_lo = byte(buf, 2)
local len = lshift(len_hi, 8) + len_lo
local data, err = sock:receive(len)
if not data then
ngx.log(ngx.ERR, "falha ao receber: ", err)
return ngx.exit(ngx.ERROR)
end
local dns = server:new()
local request, err = dns:decode_request(data)
if not request then
ngx.log(ngx.ERR, "falha ao decodificar a requisição dns: ", err)
return
end
local query = request.questions[1]
ngx.log(ngx.DEBUG, "qname: ", query.qname, " qtype: ", query.qtype)
local subnet = request.subnet[1]
if subnet then
ngx.log(ngx.DEBUG, "endereço da subnet: ", subnet.address, " máscara: ", subnet.mask, " família: ", subnet.family)
end
if query.qtype == server.TYPE_CNAME or query.qtype == server.TYPE_A then
dns:create_cname_answer(query.qname, 600, "sinacloud.com")
elseif query.qtype == server.TYPE_AAAA then
local resp_header, err = dns:create_response_header(server.RCODE_NOT_IMPLEMENTED)
resp_header.ra = 0
else
dns:create_soa_answer("test.com", 600, "a.root-test.com", "vislee.test.com", 1515161223, 1800, 900, 604800, 86400)
end
local resp = dns:encode_response()
local len = #resp
local len_hi = char(rshift(len, 8))
local len_lo = char(band(len, 0xff))
local ok, err = sock:send({len_hi, len_lo, resp})
if not ok then
ngx.log(ngx.ERR, "falha ao enviar: ", err)
return
end
return
}
}
}
Métodos
new
syntax: s, err = class:new()
Cria um objeto dns.server. Retorna nil e uma string de mensagem em caso de erro.
decode_request
syntax: request, err = s:decode_request(buf)
Analisa a requisição DNS.
A requisição retornada é uma tabela lua que contém alguns dos seguintes campos:
-
header: Oheadertambém é uma tabela lua que geralmente contém alguns dos seguintes campos:id: O identificador atribuído pelo programa que gera qualquer tipo de consulta.qr: O campo especifica se esta mensagem é uma consulta (0), ou uma resposta (1).opcode: O campo especifica o tipo de consulta nesta mensagem.tc: O campo especifica que esta mensagem foi truncada devido a um comprimento maior do que o permitido no canal de transmissão.rd: Recursão desejada. SeRDestiver definido, ele direciona o servidor de nomes a seguir a consulta recursivamente.rcode: código de resposta.qdcount: O campo que especifica o número de entradas na seção de perguntas.
-
questions: Cada entrada emquestionstambém é uma tabela lua que contém alguns dos seguintes campos:qname: Um nome de domínio da consulta.qtype: Especifica o tipo da consulta.qclass: Especifica a classe da consulta. Geralmente o campo éINpara a Internet.
create_a_answer
syntax: err = s:create_a_answer(name, ttl, ipv4)
Cria os registros A. Retorna nil ou uma string de mensagem em caso de erro.
que geralmente contém alguns dos seguintes campos:
-
nameO nome do registro de recurso. *
ttlO valor de tempo de vida (TTL) em segundos para o registro de recurso atual. *
ipv4O endereço IPv4.
create_aaaa_answer
syntax: err = s:create_aaaa_answer(name, ttl, ipv6)
Cria os registros AAAA. Retorna nil ou uma string de mensagem em caso de erro.
que geralmente contém alguns dos seguintes campos:
-
nameO nome do registro de recurso. *
ttlO valor de tempo de vida (TTL) em segundos para o registro de recurso atual. *
ipv6O endereço IPv6.
create_cname_answer
syntax: err = s:create_cname_answer(name, ttl, cname)
Cria os registros CNAME. Retorna nil ou uma string de mensagem em caso de erro.
que geralmente contém alguns dos seguintes campos:
-
nameO nome do registro de recurso. *
ttlO valor de tempo de vida (TTL) em segundos para o registro de recurso atual. *
cnameO nome para um alias.
create_txt_answer
syntax: err = s:create_txt_answer(name, ttl, txt)
Cria os registros txt. Retorna nil ou uma string de mensagem em caso de erro.
que geralmente contém alguns dos seguintes campos:
-
nameO nome do registro de recurso. *
ttlO valor de tempo de vida (TTL) em segundos para o registro de recurso atual. *
txtAs strings de texto.
create_ns_answer
syntax: err = s:create_ns_answer(name, ttl, nsdname)
Cria os registros NS. Retorna nil ou uma string de mensagem em caso de erro.
que geralmente contém alguns dos seguintes campos:
-
nameO nome do registro de recurso. *
ttlO valor de tempo de vida (TTL) em segundos para o registro de recurso atual. *
nsdnameEspecifica um host que deve ser autoritativo para a classe e domínio especificados.
create_soa_answer
syntax: err = s:create_soa_answer(name, ttl, mname, rname, serial, refresh, retry, expire, minimum)
Cria os registros SOA. Retorna nil ou uma string de mensagem em caso de erro.
que geralmente contém alguns dos seguintes campos:
-
nameO nome do registro de recurso. *
ttlO valor de tempo de vida (TTL) em segundos para o registro de recurso atual. *
mnameO servidor de nomes que foi a fonte original ou primária de dados para esta zona. *
rnameA caixa de correio da pessoa responsável por esta zona. *
serialO número da versão não assinado de 32 bits da cópia original da zona. *
refreshUm intervalo de tempo de 32 bits antes que a zona deva ser atualizada. *
retryUm intervalo de tempo de 32 bits que deve passar antes que uma atualização falhada deva ser tentada novamente. *
expireUm valor de tempo de 32 bits que especifica o limite superior do intervalo de tempo que pode passar antes que a zona não seja mais autoritativa. *
minimumO campo mínimo TTL não assinado de 32 bits que deve ser exportado com qualquer RR desta zona.
create_mx_answer
syntax: err = s:create_mx_answer(name, ttl, preference, exchange)
Cria os registros MX. Retorna nil ou uma string de mensagem em caso de erro.
que geralmente contém alguns dos seguintes campos:
-
nameO nome do registro de recurso. *
ttlO valor de tempo de vida (TTL) em segundos para o registro de recurso atual. *
preferenceA preferência deste intercâmbio de correio. *
exchangeO intercâmbio de correio.
create_srv_answer
syntax: err = s:create_srv_answer(name, ttl, priority, weight, port, target)
Cria os registros SRV. Retorna nil ou uma string de mensagem em caso de erro.
que geralmente contém alguns dos seguintes campos:
-
nameO nome do registro de recurso. *
ttlO valor de tempo de vida (TTL) em segundos para o registro de recurso atual. *
priorityA prioridade deste host alvo. *
weightO campo de peso especifica um peso relativo para entradas com a mesma prioridade. *
portA porta deste host alvo deste serviço. *
targetO nome de domínio do host alvo.
create_response_header
syntax: resp_header, err = s:create_response_header(rcode)
encode_response
syntax: resp = s:encode_response()
Codifica as respostas DNS. Retorna uma string de mensagem na resposta ou nil.
Constantes
TYPE_A
O tipo de registro de recurso A, igual ao número decimal 1.
TYPE_NS
O tipo de registro de recurso NS, igual ao número decimal 2.
TYPE_CNAME
O tipo de registro de recurso CNAME, igual ao número decimal 5.
TYPE_SOA
O tipo de registro de recurso SOA, igual ao número decimal 6.
TYPE_MX
O tipo de registro de recurso MX, igual ao número decimal 15.
TYPE_TXT
O tipo de registro de recurso TXT, igual ao número decimal 16.
TYPE_AAAA
syntax: typ = s.TYPE_AAAA
O tipo de registro de recurso AAAA, igual ao número decimal 28.
TYPE_SRV
syntax: typ = s.TYPE_SRV
O tipo de registro de recurso SRV, igual ao número decimal 33.
Veja a RFC 2782 para detalhes.
TYPE_ANY
syntax: typ = s.TYPE_ANY
O tipo de registro de recurso todos, igual ao número decimal 255.
RCODE_FORMAT_ERROR
RCODE_NOT_IMPLEMENTED
Veja Também
- o módulo stream-lua-nginx: https://github.com/openresty/stream-lua-nginx-module/#readme
- a biblioteca lua-resty-dns.
- esta biblioteca ngx_stream_ipdb_module pode suportar resolução de região.
GitHub
Você pode encontrar dicas adicionais de configuração e documentação para este módulo no repositório do GitHub para nginx-module-dns-server.