dns-server: pilote de serveur DNS Lua pour nginx-module-lua
Installation
Si vous n'avez pas encore configuré l'abonnement au dépôt RPM, inscrivez-vous. Ensuite, vous pouvez procéder avec les étapes suivantes.
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
Pour utiliser cette bibliothèque Lua avec NGINX, assurez-vous que nginx-module-lua est installé.
Ce document décrit lua-resty-dns-server v0.2 publié le 23 juillet 2019.
Cette bibliothèque Lua fournit un pilote de serveur DNS pour le module ngx_lua de NGINX :
https://github.com/openresty/stream-lua-nginx-module/#readme
Synopsis
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, "échec de l'obtention du socket de requête : ", err)
return ngx.exit(ngx.ERROR)
end
local req, err = sock:receive()
if not req then
ngx.log(ngx.ERR, "échec de la réception : ", 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, "échec du décodage de la requête : ", err)
local resp = dns:encode_response()
local ok, err = sock:send(resp)
if not ok then
ngx.log(ngx.ERR, "échec de l'envoi : ", 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, "adresse du sous-réseau : ", subnet.address, " masque : ", subnet.mask, " famille : ", 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, "échec de la création de la réponse 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, "échec de l'envoi : ", 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, "échec de l'obtention du socket de requête : ", err)
return ngx.exit(ngx.ERROR)
end
local buf, err = sock:receive(2)
if not buf then
ngx.log(ngx.ERR, "échec de la réception : ", 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, "échec de la réception : ", 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, "échec du décodage de la requête 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, "adresse du sous-réseau : ", subnet.address, " masque : ", subnet.mask, " famille : ", 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, "échec de l'envoi : ", err)
return
end
return
}
}
}
Méthodes
new
syntax: s, err = class:new()
Crée un objet dns.server. Renvoie nil et une chaîne de message en cas d'erreur.
decode_request
syntax: request, err = s:decode_request(buf)
Analyse la requête DNS.
La requête renvoie la table lua qui prend certains des champs suivants :
-
header: Leheaderest également une table lua qui prend généralement certains des champs suivants :id: L'identifiant attribué par le programme qui génère tout type de requête.qr: Le champ spécifie si ce message est une requête (0), ou une réponse (1).opcode: Le champ spécifie le type de requête dans ce message.tc: Le champ spécifie que ce message a été tronqué en raison d'une longueur supérieure à celle autorisée sur le canal de transmission.rd: Récursion désirée. SiRDest défini, il dirige le serveur de noms à poursuivre la requête de manière récursive.rcode: code de réponse.qdcount: Le champ spécifiant le nombre d'entrées dans la section des questions.
-
questions: Chaque entrée dans lesquestionsest également une table lua qui prend certains des éléments suivants :qname: Un nom de domaine de requête.qtype: Spécifie le type de la requête.qclass: Spécifie la classe de la requête. Généralement, le champ estINpour Internet.
create_a_answer
syntax: err = s:create_a_answer(name, ttl, ipv4)
Crée les enregistrements A. Renvoie nil ou une chaîne de message en cas d'erreur.
qui prend généralement certains des champs suivants :
-
nameLe nom de l'enregistrement de ressource. *
ttlLa valeur de durée de vie (TTL) en secondes pour l'enregistrement de ressource actuel. *
ipv4L'adresse IPv4.
create_aaaa_answer
syntax: err = s:create_aaaa_answer(name, ttl, ipv6)
Crée les enregistrements AAAA. Renvoie nil ou une chaîne de message en cas d'erreur.
qui prend généralement certains des champs suivants :
-
nameLe nom de l'enregistrement de ressource. *
ttlLa valeur de durée de vie (TTL) en secondes pour l'enregistrement de ressource actuel. *
ipv6L'adresse IPv6.
create_cname_answer
syntax: err = s:create_cname_answer(name, ttl, cname)
Crée les enregistrements CNAME. Renvoie nil ou une chaîne de message en cas d'erreur.
qui prend généralement certains des champs suivants :
-
nameLe nom de l'enregistrement de ressource. *
ttlLa valeur de durée de vie (TTL) en secondes pour l'enregistrement de ressource actuel. *
cnameLe nom pour un alias.
create_txt_answer
syntax: err = s:create_txt_answer(name, ttl, txt)
Crée les enregistrements txt. Renvoie nil ou une chaîne de message en cas d'erreur.
qui prend généralement certains des champs suivants :
-
nameLe nom de l'enregistrement de ressource. *
ttlLa valeur de durée de vie (TTL) en secondes pour l'enregistrement de ressource actuel. *
txtLes chaînes de texte.
create_ns_answer
syntax: err = s:create_ns_answer(name, ttl, nsdname)
Crée les enregistrements NS. Renvoie nil ou une chaîne de message en cas d'erreur.
qui prend généralement certains des champs suivants :
-
nameLe nom de l'enregistrement de ressource. *
ttlLa valeur de durée de vie (TTL) en secondes pour l'enregistrement de ressource actuel. *
nsdnameSpécifie un hôte qui doit être autoritaire pour la classe et le domaine spécifiés.
create_soa_answer
syntax: err = s:create_soa_answer(name, ttl, mname, rname, serial, refresh, retry, expire, minimum)
Crée les enregistrements SOA. Renvoie nil ou une chaîne de message en cas d'erreur.
qui prend généralement certains des champs suivants :
-
nameLe nom de l'enregistrement de ressource. *
ttlLa valeur de durée de vie (TTL) en secondes pour l'enregistrement de ressource actuel. *
mnameLe serveur de noms qui était la source originale ou primaire de données pour cette zone. *
rnameLa boîte aux lettres de la personne responsable de cette zone. *
serialLe numéro de version non signé de 32 bits de la copie originale de la zone. *
refreshUn intervalle de temps de 32 bits avant que la zone ne soit rafraîchie. *
retryUn intervalle de temps de 32 bits qui doit s'écouler avant qu'un rafraîchissement échoué ne soit réessayé. *
expireUne valeur de temps de 32 bits qui spécifie la limite supérieure sur l'intervalle de temps qui peut s'écouler avant que la zone ne soit plus autoritaire. *
minimumLe champ TTL minimum non signé de 32 bits qui doit être exporté avec tout RR de cette zone.
create_mx_answer
syntax: err = s:create_mx_answer(name, ttl, preference, exchange)
Crée les enregistrements MX. Renvoie nil ou une chaîne de message en cas d'erreur.
qui prend généralement certains des champs suivants :
-
nameLe nom de l'enregistrement de ressource. *
ttlLa valeur de durée de vie (TTL) en secondes pour l'enregistrement de ressource actuel. *
preferenceLa préférence de cet échange de courrier. *
exchangeL'échange de courrier.
create_srv_answer
syntax: err = s:create_srv_answer(name, ttl, priority, weight, port, target)
Crée les enregistrements SRV. Renvoie nil ou une chaîne de message en cas d'erreur.
qui prend généralement certains des champs suivants :
-
nameLe nom de l'enregistrement de ressource. *
ttlLa valeur de durée de vie (TTL) en secondes pour l'enregistrement de ressource actuel. *
priorityLa priorité de cet hôte cible. *
weightLe champ de poids spécifie un poids relatif pour les entrées avec la même priorité. *
portLe port sur cet hôte cible de ce service. *
targetLe nom de domaine de l'hôte cible.
create_response_header
syntax: resp_header, err = s:create_response_header(rcode)
encode_response
syntax: resp = s:encode_response()
Encode les réponses DNS. Renvoie une chaîne de message sur la réponse ou nil.
Constantes
TYPE_A
Le type d'enregistrement de ressource A, égal au nombre décimal 1.
TYPE_NS
Le type d'enregistrement de ressource NS, égal au nombre décimal 2.
TYPE_CNAME
Le type d'enregistrement de ressource CNAME, égal au nombre décimal 5.
TYPE_SOA
Le type d'enregistrement de ressource SOA, égal au nombre décimal 6.
TYPE_MX
Le type d'enregistrement de ressource MX, égal au nombre décimal 15.
TYPE_TXT
Le type d'enregistrement de ressource TXT, égal au nombre décimal 16.
TYPE_AAAA
syntax: typ = s.TYPE_AAAA
Le type d'enregistrement de ressource AAAA, égal au nombre décimal 28.
TYPE_SRV
syntax: typ = s.TYPE_SRV
Le type d'enregistrement de ressource SRV, égal au nombre décimal 33.
Voir RFC 2782 pour plus de détails.
TYPE_ANY
syntax: typ = s.TYPE_ANY
Le type d'enregistrement de ressource tous, égal au nombre décimal 255.
RCODE_FORMAT_ERROR
RCODE_NOT_IMPLEMENTED
Voir aussi
- le module stream-lua-nginx : https://github.com/openresty/stream-lua-nginx-module/#readme
- la bibliothèque lua-resty-dns.
- cette bibliothèque ngx_stream_ipdb_module peut prendre en charge la résolution régionale.
GitHub
Vous pouvez trouver des conseils de configuration supplémentaires et de la documentation pour ce module dans le dépôt GitHub pour nginx-module-dns-server.