dns-server: controlador de servidor DNS Lua para nginx-module-lua
Instalación
Si no has configurado la suscripción al repositorio RPM, regístrate. Luego puedes proceder con los siguientes pasos.
CentOS/RHEL 7 o 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 con NGINX, asegúrate de que nginx-module-lua esté instalado.
Este documento describe lua-resty-dns-server v0.2 lanzado el 23 de julio de 2019.
Esta biblioteca Lua proporciona un controlador de servidor DNS para el módulo ngx_lua de nginx:
https://github.com/openresty/stream-lua-nginx-module/#readme
Sinopsis
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, "falló al obtener el socket de la solicitud: ", err)
return ngx.exit(ngx.ERROR)
end
local req, err = sock:receive()
if not req then
ngx.log(ngx.ERR, "falló al recibir: ", 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, "falló al decodificar la solicitud: ", err)
local resp = dns:encode_response()
local ok, err = sock:send(resp)
if not ok then
ngx.log(ngx.ERR, "falló al 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, "subnet addr: ", subnet.address, " mask: ", subnet.mask, " family: ", 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, "falló al crear la respuesta 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, "falló al 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, "falló al obtener el socket de la solicitud: ", err)
return ngx.exit(ngx.ERROR)
end
local buf, err = sock:receive(2)
if not buf then
ngx.log(ngx.ERR, "falló al recibir: ", 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, "falló al recibir: ", 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, "falló al decodificar la solicitud 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, "subnet addr: ", subnet.address, " mask: ", subnet.mask, " family: ", 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, "falló al enviar: ", err)
return
end
return
}
}
}
Métodos
new
syntax: s, err = class:new()
Crea un objeto dns.server. Devuelve nil y un mensaje de error en caso de fallo.
decode_request
syntax: request, err = s:decode_request(buf)
Analiza la solicitud DNS.
La solicitud devuelve la tabla lua que contiene algunos de los siguientes campos:
-
header: Elheaderes también una tabla lua que generalmente contiene algunos de los siguientes campos:id: El identificador asignado por el programa que genera cualquier tipo de consulta.qr: El campo especifica si este mensaje es una consulta (0), o una respuesta (1).opcode: El campo especifica el tipo de consulta en este mensaje.tc: El campo especifica que este mensaje fue truncado debido a una longitud mayor a la permitida en el canal de transmisión.rd: Recursión deseada. SiRDestá configurado, dirige al servidor de nombres a seguir la consulta de manera recursiva.rcode: código de respuesta.qdcount: El campo que especifica el número de entradas en la sección de preguntas.
-
questions: Cada entrada enquestionses también una tabla lua que contiene algunos de los siguientes:qname: Un nombre de dominio de consulta.qtype: Especifica el tipo de la consulta.qclass: Especifica la clase de la consulta. Generalmente el campo esINpara Internet.
create_a_answer
syntax: err = s:create_a_answer(name, ttl, ipv4)
Crea los registros A. Devuelve nil o un mensaje de error en caso de fallo.
que generalmente contiene algunos de los siguientes campos:
-
nameEl nombre del registro de recursos. *
ttlEl valor de tiempo de vida (TTL) en segundos para el registro de recursos actual. *
ipv4La dirección IPv4.
create_aaaa_answer
syntax: err = s:create_aaaa_answer(name, ttl, ipv6)
Crea los registros AAAA. Devuelve nil o un mensaje de error en caso de fallo.
que generalmente contiene algunos de los siguientes campos:
-
nameEl nombre del registro de recursos. *
ttlEl valor de tiempo de vida (TTL) en segundos para el registro de recursos actual. *
ipv6La dirección IPv6.
create_cname_answer
syntax: err = s:create_cname_answer(name, ttl, cname)
Crea los registros CNAME. Devuelve nil o un mensaje de error en caso de fallo.
que generalmente contiene algunos de los siguientes campos:
-
nameEl nombre del registro de recursos. *
ttlEl valor de tiempo de vida (TTL) en segundos para el registro de recursos actual. *
cnameEl nombre para un alias.
create_txt_answer
syntax: err = s:create_txt_answer(name, ttl, txt)
Crea los registros txt. Devuelve nil o un mensaje de error en caso de fallo.
que generalmente contiene algunos de los siguientes campos:
-
nameEl nombre del registro de recursos. *
ttlEl valor de tiempo de vida (TTL) en segundos para el registro de recursos actual. *
txtLas cadenas de texto.
create_ns_answer
syntax: err = s:create_ns_answer(name, ttl, nsdname)
Crea los registros NS. Devuelve nil o un mensaje de error en caso de fallo.
que generalmente contiene algunos de los siguientes campos:
-
nameEl nombre del registro de recursos. *
ttlEl valor de tiempo de vida (TTL) en segundos para el registro de recursos actual. *
nsdnameEspecifica un host que debe ser autoritativo para la clase y dominio especificados.
create_soa_answer
syntax: err = s:create_soa_answer(name, ttl, mname, rname, serial, refresh, retry, expire, minimum)
Crea los registros SOA. Devuelve nil o un mensaje de error en caso de fallo.
que generalmente contiene algunos de los siguientes campos:
-
nameEl nombre del registro de recursos. *
ttlEl valor de tiempo de vida (TTL) en segundos para el registro de recursos actual. *
mnameEl servidor de nombres que fue la fuente original o primaria de datos para esta zona. *
rnameEl buzón de la persona responsable de esta zona. *
serialEl número de versión sin signo de 32 bits de la copia original de la zona. *
refreshUn intervalo de tiempo de 32 bits antes de que la zona deba ser refrescada. *
retryUn intervalo de tiempo de 32 bits que debe transcurrir antes de que se intente nuevamente un refresco fallido. *
expireUn valor de tiempo de 32 bits que especifica el límite superior en el intervalo de tiempo que puede transcurrir antes de que la zona ya no sea autoritativa. *
minimumEl campo mínimo TTL de 32 bits sin signo que debe ser exportado con cualquier RR de esta zona.
create_mx_answer
syntax: err = s:create_mx_answer(name, ttl, preference, exchange)
Crea los registros MX. Devuelve nil o un mensaje de error en caso de fallo.
que generalmente contiene algunos de los siguientes campos:
-
nameEl nombre del registro de recursos. *
ttlEl valor de tiempo de vida (TTL) en segundos para el registro de recursos actual. *
preferenceLa preferencia de este intercambio de correo. *
exchangeEl intercambio de correo.
create_srv_answer
syntax: err = s:create_srv_answer(name, ttl, priority, weight, port, target)
Crea los registros SRV. Devuelve nil o un mensaje de error en caso de fallo.
que generalmente contiene algunos de los siguientes campos:
-
nameEl nombre del registro de recursos. *
ttlEl valor de tiempo de vida (TTL) en segundos para el registro de recursos actual. *
priorityLa prioridad de este host objetivo. *
weightEl campo de peso especifica un peso relativo para las entradas con la misma prioridad. *
portEl puerto en este host objetivo de este servicio. *
targetEl nombre de dominio del host objetivo.
create_response_header
syntax: resp_header, err = s:create_response_header(rcode)
encode_response
syntax: resp = s:encode_response()
Codifica las respuestas DNS. Devuelve un mensaje de respuesta o nil.
Constantes
TYPE_A
El tipo de registro de recursos A, igual al número decimal 1.
TYPE_NS
El tipo de registro de recursos NS, igual al número decimal 2.
TYPE_CNAME
El tipo de registro de recursos CNAME, igual al número decimal 5.
TYPE_SOA
El tipo de registro de recursos SOA, igual al número decimal 6.
TYPE_MX
El tipo de registro de recursos MX, igual al número decimal 15.
TYPE_TXT
El tipo de registro de recursos TXT, igual al número decimal 16.
TYPE_AAAA
syntax: typ = s.TYPE_AAAA
El tipo de registro de recursos AAAA, igual al número decimal 28.
TYPE_SRV
syntax: typ = s.TYPE_SRV
El tipo de registro de recursos SRV, igual al número decimal 33.
Consulta el RFC 2782 para más detalles.
TYPE_ANY
syntax: typ = s.TYPE_ANY
El tipo de registro de recursos todos, igual al número decimal 255.
RCODE_FORMAT_ERROR
RCODE_NOT_IMPLEMENTED
Ver También
- el módulo stream-lua-nginx: https://github.com/openresty/stream-lua-nginx-module/#readme
- la biblioteca lua-resty-dns.
- esta biblioteca ngx_stream_ipdb_module puede soportar resolución de región.
GitHub
Puedes encontrar consejos adicionales de configuración y documentación para este módulo en el repositorio de GitHub para nginx-module-dns-server.