DNS Lua Service
Introduction
The DnsLuaService is a service for initiating Lua scripts running within the LogicApp.
The DnsLuaService receives messages from one or more instances of the DnsServerApp which is configured to receive DNS (typically ENUM) Requests from an external client.
The DnsLuaService communicates with the DnsServerApp using the DNS-S-… messages.
Configuring DnsLuaService
The DnsLuaService is configured within a LogicApp.
<?xml version="1.0" encoding="utf-8"?>
<n2svcd>
...
<applications>
...
<application name="Logic" module="LogicApp">
<include>
<lib>../apps/logic/lib</lib>
</include>
<parameters>
...
</parameters>
<config>
<services>
<service module="DnsServerApp::DnsLuaService" libs="../apps/dns_s/lib" script_dir="/var/lib/n2svcd/logic/dns"/>
</services>
<agents>
...
</agents>
</config>
</application>
...
</application>
...
</n2svcd>
In addition to the Common LogicApp Service Configuration, note the following specific attribute notes, and service-specific attributes.
Under normal installation, the following service
attributes apply:
Parameter Name | Type | XML Type | Description |
---|---|---|---|
module
|
String | Attribute |
[Required] The module name containing the Lua Service code: DnsServerApp::DnsLuaService
|
libs
|
String | Attribute |
Location of the module for DnsLuaService.(Default: ../apps/dns_s/lib )
|
script_dir
|
String | Attribute | [Required] The directory containing scripts used by this service. |
Script Selection (DNS Request)
Script selection is not configured. The script key to be executed is determined by the numeric opcode
value of the inbound DNS request represented in the DNS-S-REQUEST message.
Specifically:
- Opcode
0
will execute script keyquery
. - Opcode
1
will execute script keyiquery
. - Opcode
2
will execute script keystatus
. - Opcodes
3
-15
will execute script keyopcode_<number>
e.g.opcode_3
.
E.g. standard query requests with opcode = 0
will be satisfied by a file
named query.lua
or query.lc
in the script_dir
directory configured
for the service.
Refer to the LogicApp configuration for more information on directories, library paths, and script caching parameters.
Script Global Variables
Scripts run with this service have access to the Common LUA Service Global Variables.
There are no service-specific global variables.
Script Entry Parameters (DNS Request)
The Lua script must be a Lua chunk such as the following
example for an E.164 lookup which always returns the indicated regex for the SIP+E2U
service:
local n2svcd = require "n2.n2svcd"
local dns = ...
n2svcd.debug ("Echo Supplied DNS Inputs:")
n2svcd.debug_var (dns)
return {
reply_code = 0,
answers = {
{ class = 1, type = 35, name = dns.queries[1].name, service = 'SIP+E2U', regex = '!^.*$!sip:16133957218@example.com!' }
}
}
The chunk will be executed with a single dns
entry parameter which is an object with the
following attributes:
Attribute | Type | Description |
---|---|---|
.remote_ip
|
String | The remote dot-notation IP address from which the DNS request was sent. |
.remote_port
|
Integer | The remote UDP or TCP port from which the DNS request was sent. |
.transaction_id
|
0 - 65535
|
The two-byte transaction ID as an integer value. |
.flags
|
Integer | An integer representation of the top-level DNS message two-byte flags field. |
.reply_code
|
Integer |
An integer representation of the 4-bit reply code value from the flags field. This should always be zero for inbound requests. |
.opcode
|
Integer | An integer representation of the 4-bit opcode value from the flags field. |
.recursion_desired
|
0 / 1
|
An integer representation of the 1-bit RD value from the flags field. |
.checking_disabled
|
0 / 1
|
An integer representation of the 1-bit CD value from the flags field. |
.num_questions
|
Integer |
The number of entries contained in the questions section of the DNS request. For a standard query with opcode = 0 , at least one question should be present.
|
.num_answers
|
Integer |
The number of entries contained in the answers section of the DNS request. For an inverse query with opcode = 1 , at least one answer should be present.
|
.num_authorities
|
Integer |
The number of entries contained in the authorities section of the DNS request. This should be zero in any normal scenario for both standard query or inverse query. |
.num_additional
|
Integer |
The number of entries contained in the additional section of the DNS request. This should be zero in any normal scenario for both standard query or inverse query. |
.queries
|
Array of Object | The list of Query records parsed from the DNS Request (see below for object structure). |
.authorities
|
Array of Object | The list of Authority response records parsed from the DNS Request (see below for object structure). |
.additional
|
Array of Object | The list of Additional response records parsed from the DNS Request (see below for object structure). |
.answers
|
Array of Object | The list of Answer response records parsed from the DNS Request (see below for object structure). |
The queries
Object in the dns
entry parameter has the following structure.
Field | Type | Description |
---|---|---|
.name
|
String
|
[Required] The name of the record as a dot-notation string. For E.164 NAPTR records use the .e164_digits helper method to convert this to a simple digit string.
|
.type
|
Integer
|
[Required] The integer value of the Type, e.g. 35 indicating NAPTR .
|
.class
|
Integer
|
[Required] The integer value of the Class, e.g. 1 indicating IN .
|
The answers
, authorities
, and additional
Objects in the dns
entry parameter have the following structure.
Note that in normal processing, only the answers
object will be present, and that only when the top-level opcode
= 1
which indicates an inverse query.
Note that the sub-fields name
, type
, class
, ttl
are common to all of these three record
types (answers
, authorities
, and additional
) regardless of type
/class
.
All other sub-fields are specific to individual record type
values. At this time the only supported response
record types for which extra data fields will be decoded are the following:
- NAPTR (Type = 35) decoded as per RFC 2915.
Field | Type | Description |
---|---|---|
.name
|
String
|
[Required] The name of the record as a dot-notation string. |
.type
|
Integer
|
[Required] The integer value of the Type, e.g. 35 indicating NAPTR .
|
.class
|
Integer
|
[Required] The integer value of the Class, e.g. 1 indicating IN .
|
.ttl
|
Integer
|
[Required] The TTL (time-to-live) in seconds for this record. |
.order
|
Integer
|
[Required for NAPTR (Type = 35)] The Order value (0-65535) supplied in the NAPTR response record. |
.preference
|
Integer
|
[Required for NAPTR (Type = 35)] The Preference value (0-65535) supplied in the NAPTR response record. |
.flags
|
Integer
|
[Required for NAPTR (Type = 35)] An integer representation of the flags supplied in the NAPTR response record. |
.service
|
String
|
[Required for NAPTR (Type = 35)] The Service string supplied in the NAPTR response record. |
.regex
|
String
|
[Required for NAPTR (Type = 35)] The Regex string (if any) supplied in the NAPTR response record. |
.replacement
|
String
|
[Required for NAPTR (Type = 35)] The Replacement domain name (if any) supplied in the NAPTR response record, expressed as a dot-separated domain name. |
Script Return Parameters (DNS Response)
The Lua script is responsible for determing the DNS Response which will be sent back in reply to the original DNS Request.
The simplest way to do this is by the return value given back to the service at the end of script execution.
When returning an DNS response with answers, the script return value must be a response
object with the following attributes:
Field | Type | Description |
---|---|---|
response
|
Object | Container for the DNS response parameters we are to send. |
.authoritative_answer
|
0 / 1
|
Should the response set the 1-bit AA value in the top-level flags. (Default = 0 )
|
.recursion_available
|
0 / 1
|
Should the response set the 1-bit RA value in the top-level flags. (Default = 0 )
|
.authenticated_data
|
0 / 1
|
Should the response set the 1-bit AD value in the top-level flags. (Default = 0 )
|
.reply_code
|
0 - 15
|
[Required] The top-level 4-bit Reply Code to set in the top-level flags. A value of 0 indicates success and should always be used when returning any answer entries.
|
.queries
|
Array of Object |
The list of Query records to return as DNS Response (see below for object structure). The default behavior (when reply_code = 0 for success) is to copy the inbound DNS query records back into the response.
If this is not desirable then you may explicitly specify an array of queries records in the response.If you explicitly require no queries in the response then set the queries attribute to be the UNDEF constant.
(Default: Copy the inbound DNS Request query records back out into the DNS Response)
|
.authorities
|
Array of Object | The list of Authority response records to return as DNS Response (see below for object structure). |
.additional
|
Array of Object | The list of Additional response records to return as DNS Response (see below for object structure). |
.answers
|
Array of Object | The list of Answer response records to return as DNS Response (see below for object structure). |
Note that many of the return flags and values in the DNS Response are set automatically and cannot be controlled by the service logic.
Specifically:
- The returned flags bit field for Response is always
1
for “Response”. - The returned flags 4-bit field for opcode is always set to match the incoming opcode.
- The returned flags bit field for Truncated is set automatically if the response is truncated.
- The returned flags bit field for
RD
(Recursion Desired) is copied to match the incoming value. - The returned flags bit field for Checking Disabled is always
0
.
The queries
Object in the returned DNS response argument has the following structure.
Note that typically it is not required to set this value, instead the inbound request queries
array will be copied back into the response. This copy-back is performed by the DnsServerApp
when it constructs the on-the-wire response message, and is performed only when the reply code is
0
indicating success.
Field | Type | Description |
---|---|---|
.name
|
String
|
[Required] The name of the record as a dot-notation string. |
.type
|
Integer
|
[Required] The integer value of the Type, e.g. 35 indicating NAPTR .
|
.class
|
Integer
|
[Required] The integer value of the Class, e.g. 1 indicating IN .
|
The answers
, authorities
, and additional
Objects in the returned DNS response argument have the following structure.
Note that the sub-fields name
, type
, class
, ttl
are common to all of these three record
types (answers
, authorities
, and additional
) regardless of type
/class
.
All other sub-fields are specific to individual record type
values. At this time the only supported response
record types for which extra data fields will be encoded are the following:
- NAPTR (Type = 35) encoded as per RFC 2915.
Field | Type | Description |
---|---|---|
.name
|
String
|
[Required] The name of the record as a dot-notation string. For an answers record this might be copied from the received queries list.
|
.type
|
Integer
|
[Required] The integer value of the Type, e.g. 35 indicating NAPTR .
|
.class
|
Integer
|
[Required] The integer value of the Class, e.g. 1 indicating IN .
|
.ttl
|
Integer
|
The TTL (time-to-live) in seconds for this record. You should generally set this value explicitly. (Default = 300 )
|
.order
|
Integer
|
[Applies for NAPTR (Type = 35)] The Order value (0-65535) supplied in the NAPTR response record. (Default: The first record of each list will be given order 10 , the next 20 , etc.)
|
.preference
|
Integer
|
[Applies for NAPTR (Type = 35)] The Preference value (0-65535) supplied in the NAPTR response record. (Default = 1 )
|
.flags
|
Integer
|
[Applies for NAPTR (Type = 35)] An integer representation of the flags supplied in the NAPTR response record. (Default = 0 )
|
.service
|
String
|
[Required for NAPTR (Type = 35)] The Service string supplied in the NAPTR response record. |
.regex
|
String
|
[Required for NAPTR (Type = 35)] The Regex string (if any) supplied in the NAPTR response record. |
.replacement
|
String
|
[Applies for NAPTR (Type = 35)] The Replacement domain name (if any) supplied in the NAPTR
response record, expressed as a dot-separated domain name. (Default = '' )
|
Example (returning a Table DNS Response):
local n2svcd = require "n2.n2svcd"
local dns = ...
return ({
reply_code = 0,
answers = {
{ class = 1, type = 35, name = dns.queries[1].name, service = 'SIP+E2U', regex = '!^.*$!sip:16133957218@example.com!' }
}
})
Alternatively, a script may return a simple Lua number value as the result, which indicates an reply_code with no additional returned records.
Typically the reply code should be non-zero in this case.
Example (returning explicit error):
local n2svcd = require "n2.n2svcd"
local dns = ...
-- Reply Code 4 = NOTIMP Function not implemented
return 4
i.e. return 4
is shorthand for return { reply_code = 4 }
.
Alternatively, a script may return nil
.
This will cause the return of an DNS success response with reply code = 0
but with an empty answers
section.
Example (success returning no answers):
local n2svcd = require "n2.n2svcd"
local dns = ...
return nil
i.e. return nil
is shorthand for return { reply_code = 0 }
.
The DnsLuaService API
The DNS Service API can be loaded as follows.
local dns_service = require "n2.n2svcd.dns_service"
It is not necessary to load the DNS Service API if you are only using the simple response mechanism described above. It is only required if you wish to use any of the extended features described below.
.response
When a Lua Script needs to perform extended processing, it may wish to send an early
response before the script completes. This can be done with the response
method on the
DNS API.
The response
method takes a single response
parameter. The structure of this
response parameter must be a table, with structure as per the response
return value
described above in
Script Return Parameters (DNS Response)
The shorthand return values for nil
and for Lua number values are not available
when using this method.
The response
method returns true
.
[Fragment] Example (Full table early response):
...
dns_service.response ({
reply_code = 0,
answers = {
{ class = 1, type = 35, name = dns.queries[1].name, service = 'SIP+E2U', regex = '!^.*$!sip:16133957218@example.com!' }
}
})
...
[post-processing after DNS transaction is concluded]
...
.e164_digits [Pure Lua]
The e164_digits
method is a helper method to facilitate the processing of received ENUM NAPTR lookup requests.
This method accepts the following parameters:
Field | Type | Description |
---|---|---|
dns
|
String | [Required] The received DNS request object as passed in the first parameter to the service script. |
suffix
|
Table |
An optional override for the E.164 suffix string which must be matched before the name is considered an E.164 digit string. (Default = 'e164.org' ).
|
This method returns a string which is the E.164 digits (without leading +
) in the case where the first query record
is an NAPTR record which contains a name field with the expected E.164 suffix. In all other cases it will return nil
.
[Fragment] Example:
local n2svcd = require "n2.n2svcd"
local dns = ...
local e164_digits = dns_agent.e164_digits (dns)
if (e164_digits ~= nil) then
if (e164_digits == '642711209400') then
...
Constants
The following DNS and DNS constants are defined on the returned dns_service
object.
See:
- RFC 1035 Domain Implementation and Specification
- RFC 2915 The Naming Authority Pointer (NAPTR) DNS Resource Record
-- DNS Type Constants.
dns_service.TYPE_NS = 2
dns_service.TYPE_NAPTR = 35
-- DNS Class Constants.
dns_service.CLASS_IN = 1
-- DNS OPCODE Constants.
dns_service.OPCODE_QUERY = 0
dns_service.OPCODE_IQUERY = 1
dns_service.OPCODE_STATUS = 2
-- DNS REPLY CODE Constants.
dns_service.RCODE_NOERROR = 0 -- DNS Query completed successfully
dns_service.RCODE_FORMERR = 1 -- DNS Query Format Error
dns_service.RCODE_SERVFAIL = 2 -- Server failed to complete the DNS request
dns_service.RCODE_NXDOMAIN = 3 -- Domain name does not exist
dns_service.RCODE_NOTIMP = 4 -- Function not implemented
dns_service.RCODE_REFUSED = 5 -- The server refused to answer for the query
dns_service.RCODE_YXDOMAIN = 6 -- Name that should not exist, does exist
dns_service.RCODE_XRRSET = 7 -- RRset that should not exist, does exist
dns_service.RCODE_NOTAUTH = 8 -- Server not authoritative for the zone
dns_service.RCODE_NOTZONE = 9 -- Name not in zone