Saltar a contenido

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: El header es 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. Si RD está 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 en questions es 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 es IN para 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:

  • name

    El nombre del registro de recursos. * ttl

    El valor de tiempo de vida (TTL) en segundos para el registro de recursos actual. * ipv4

    La 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:

  • name

    El nombre del registro de recursos. * ttl

    El valor de tiempo de vida (TTL) en segundos para el registro de recursos actual. * ipv6

    La 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:

  • name

    El nombre del registro de recursos. * ttl

    El valor de tiempo de vida (TTL) en segundos para el registro de recursos actual. * cname

    El 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:

  • name

    El nombre del registro de recursos. * ttl

    El valor de tiempo de vida (TTL) en segundos para el registro de recursos actual. * txt

    Las 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:

  • name

    El nombre del registro de recursos. * ttl

    El valor de tiempo de vida (TTL) en segundos para el registro de recursos actual. * nsdname

    Especifica 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:

  • name

    El nombre del registro de recursos. * ttl

    El valor de tiempo de vida (TTL) en segundos para el registro de recursos actual. * mname

    El servidor de nombres que fue la fuente original o primaria de datos para esta zona. * rname

    El buzón de la persona responsable de esta zona. * serial

    El número de versión sin signo de 32 bits de la copia original de la zona. * refresh

    Un intervalo de tiempo de 32 bits antes de que la zona deba ser refrescada. * retry

    Un intervalo de tiempo de 32 bits que debe transcurrir antes de que se intente nuevamente un refresco fallido. * expire

    Un 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. * minimum

    El 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:

  • name

    El nombre del registro de recursos. * ttl

    El valor de tiempo de vida (TTL) en segundos para el registro de recursos actual. * preference

    La preferencia de este intercambio de correo. * exchange

    El 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:

  • name

    El nombre del registro de recursos. * ttl

    El valor de tiempo de vida (TTL) en segundos para el registro de recursos actual. * priority

    La prioridad de este host objetivo. * weight

    El campo de peso especifica un peso relativo para las entradas con la misma prioridad. * port

    El puerto en este host objetivo de este servicio. * target

    El 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

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.