BrainicHQ / lua-resty-dns-server

Lua DNS server driver for OpenResty

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Name

Build Status

lua-resty-dns-server - Lua DNS server driver for the OpenResty

Table of Contents

Status

This library is still under early development and is still experimental.

Description

This Lua library provies a DNS server driver for the ngx_lua nginx module:

https://github.com/openresty/stream-lua-nginx-module/#readme

Synopsis

lua_package_path "/path/to/lua-resty-dns-server/lib/?.lua;;";

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, "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 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, "failed to create cname answer: ", 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, "failed to send: ", 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, "failed to get the request socket: ", err)
                return ngx.exit(ngx.ERROR)
            end

            local buf, err = sock:receive(2)
            if not buf then
                ngx.log(ngx.ERR, "failed to receive: ", 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, "failed to receive: ", 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, "failed to decode dns request: ", 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, "failed to send: ", err)
                return
            end
            return
        }
    }
}

Back to TOC

Methods

Back to TOC

new

syntax: s, err = class:new()

Creates a dns.server object. Returns nil and an message string on error.

Back to TOC

decode_request

syntax: request, err = s:decode_request(buf)

Parse the DNS request.

The request returned the lua table which takes some of the following fields:

  • header: The header is also a lua table which usually takes some of the following fields:

    • id : The identifier assigned by the program that generates any kind of query.
    • qr : The field specifies whether this message is a query (0), or a response (1).
    • opcode : The field specifies kind of query in this message.
    • tc : The field specifies that this message was truncated due to length greater than that permitted on the transmission channel.
    • rd : Recursion Desired. If RD is set, it directs the name server to pursue the query recursively.
    • rcode : response code.
    • qdcount : The field specifying the number of entries in the question section.
  • questions : Each entry in the questions is also a lua table which takes some of the following:

    • qname : A domain name of query.
    • qtype : Specifies the type of the query.
    • qclass : Specifies the class of the query. Usually the field is IN for the Internet.

Back to TOC

create_a_answer

syntax: err = s:create_a_answer(name, ttl, ipv4)

Create the A records. Returns nil or an message string on error. which usually takes some of the following fields:

  • name

    The resource record name.

  • ttl

    The time-to-live (TTL) value in seconds for the current resource record.

  • ipv4

    The IPv4 address.

Back to TOC

create_aaaa_answer

syntax: err = s:create_aaaa_answer(name, ttl, ipv6)

Create the AAAA records. Returns nil or an message string on error. which usually takes some of the following fields:

  • name

    The resource record name.

  • ttl

    The time-to-live (TTL) value in seconds for the current resource record.

  • ipv6

    The IPv6 address.

Back to TOC

create_cname_answer

syntax: err = s:create_cname_answer(name, ttl, cname)

Create the CNAME records. Returns nil or an message string on error. which usually takes some of the following fields:

  • name

    The resource record name.

  • ttl

    The time-to-live (TTL) value in seconds for the current resource record.

  • cname

    The name for an alias.

Back to TOC

create_txt_answer

syntax: err = s:create_txt_answer(name, ttl, txt)

Create the txt records. Returns nil or an message string on error. which usually takes some of the following fields:

  • name

    The resource record name.

  • ttl

    The time-to-live (TTL) value in seconds for the current resource record.

  • txt

    The text strings.

Back to TOC

create_ns_answer

syntax: err = s:create_ns_answer(name, ttl, nsdname)

Create the NS records. Returns nil or an message string on error. which usually takes some of the following fields:

  • name

    The resource record name.

  • ttl

    The time-to-live (TTL) value in seconds for the current resource record.

  • nsdname

    The specifies a host which should be authoritative for the specified class and domain.

Back to TOC

create_soa_answer

syntax: err = s:create_soa_answer(name, ttl, mname, rname, serial, refresh, retry, expire, minimum)

Create the SOA records. Returns nil or an message string on error. which usually takes some of the following fields:

  • name

    The resource record name.

  • ttl

    The time-to-live (TTL) value in seconds for the current resource record.

  • mname

    The the name server that was the original or primary source of data for this zone.

  • rname

    The mailbox of the person responsible for this zone.

  • serial

    The unsigned 32 bit version number of the original copy of the zone.

  • refresh

    A 32 bit time interval before the zone should be refreshed.

  • retry

    A 32 bit time interval that should elapse before a failed refresh should be retried.

  • expire

    A 32 bit time value that specifies the upper limit on the time interval that can elapse before the zone is no longer authoritative.

  • minimum

    The unsigned 32 bit minimum TTL field that should be exported with any RR from this zone.

Back to TOC

create_mx_answer

syntax: err = s:create_mx_answer(name, ttl, preference, exchange)

Create the MX records. Returns nil or an message string on error. which usually takes some of the following fields:

  • name

    The resource record name.

  • ttl

    The time-to-live (TTL) value in seconds for the current resource record.

  • preference

    The preference of this mail exchange.

  • exchange

    The mail exchange.

Back to TOC

create_srv_answer

syntax: err = s:create_srv_answer(name, ttl, priority, weight, port, target)

Create the SRV records. Returns nil or an message string on error. which usually takes some of the following fields:

  • name

    The resource record name.

  • ttl

    The time-to-live (TTL) value in seconds for the current resource record.

  • priority

    The priority of this target host.

  • weight

    The weight field specifies a relative weight for entries with the same priority.

  • port

    The port on this target host of this service.

  • target

    The domain name of the target host.

Back to TOC

create_response_header

syntax: resp_header, err = s:create_response_header(rcode)

Back to TOC

encode_response

syntax: resp = s:encode_response()

Encode the DNS answers. Returns an message string on response or nil.

Back to TOC

Constants

Back to TOC

TYPE_A

The A resource record type, equal to the decimal number 1.

Back to TOC

TYPE_NS

The NS resource record type, equal to the decimal number 2.

Back to TOC

TYPE_CNAME

The CNAME resource record type, equal to the decimal number 5.

Back to TOC

TYPE_SOA

The SOA resource record type, equal to the decimal number 6.

Back to TOC

TYPE_MX

The MX resource record type, equal to the decimal number 15.

Back to TOC

TYPE_TXT

The TXT resource record type, equal to the decimal number 16.

Back to TOC

TYPE_AAAA

syntax: typ = s.TYPE_AAAA

The AAAA resource record type, equal to the decimal number 28.

Back to TOC

TYPE_SRV

syntax: typ = s.TYPE_SRV

The SRV resource record type, equal to the decimal number 33.

See RFC 2782 for details.

Back to TOC

TYPE_ANY

syntax: typ = s.TYPE_ANY

The all resource record type, equal to the decimal number 255.

Back to TOC

RCODE_FORMAT_ERROR

Back to TOC

RCODE_NOT_IMPLEMENTED

Back to TOC

TODO

Back to TOC

Author

wenqiang li(vislee)

guocan xu(selboo)

Back to TOC

Copyright and License

This module is licensed under the BSD license.

Copyright (C) 2018-2019, by vislee.

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Back to TOC

See Also

Back to TOC

About

Lua DNS server driver for OpenResty

License:BSD 2-Clause "Simplified" License


Languages

Language:Lua 98.2%Language:Makefile 1.8%