have taken over the request, or want to let normal proceedings take their course.
</para>
<para>
- If a function has taken over a request, it should return 'true', and specify a table with records to be put in the answer section of a packet.
- Returning 'false' and an empty table signifies that the function chose not to intervene.
+ If a function has taken over a request, it should return an rcode (usually 0), and specify a table with records to be put in the answer section of a packet.
+ Returning -1 and an empty table signifies that the function chose not to intervene.
</para>
<para>
A minimal sample script:
print ("nxhandler called for: ", ip, domain, qtype)
ret={}
- if qtype ~= 1 then return false, ret end -- only A records
- if not string.match(domain, "^www.") then return false, ret end -- only things that start with www.
- if not matchnetmask(ip, "192.168.0.0/16") then return false, ret -- only interfere with local queries
-
- ret[0]={1, "127.1.2.3", 3600} -- add IN A 127.1.2.3
- ret[1]={1 "127.3.2.1", 3600} -- add IN A 127.3.2.1
- return true, ret -- return true, plus records
+ if qtype ~= 1 then return -1, ret end -- only A records
+ if not string.gmatch(domain, "^www.") then return -1, ret end -- only things that start with www.
+ if not matchnetmask(ip, "10.0.0.0/8") then return -1, ret end -- only interfere with local queries
+ ret[0]={qtype=1, content="127.1.2.3"} -- add IN A 127.1.2.3
+ ret[1]={qtype=1, content="127.3.2.1"} -- add IN A 127.3.2.1
+ return 0, ret -- return true, plus records
end
</screen>
</para>
+ <para>
+ For Lua 5.0, use <function>string.find</function> instead of <function>string.gmatch</function>.
+ </para>
<para>
<warning>
<para>
The exception is that, unlike in the datbase, there is no 'prio' field, which means that an MX record with priority 25 pointing to 'smtp.mailserver.com' would be encoded as
'25 smtp.mailserver.com.'.
</para>
+ <para>
+ Useful return 'rcodes' include 0 for "no error" and 3 for "NXDOMAIN".
+ </para>
+ <para>
+ Useful fields that can be set in the return table include:
+ <variablelist>
+ <varlistentry>
+ <term>content</term>
+ <listitem>
+ <para>
+ Content of the record, as specified above in 'zone file format'. No default, mandatory field.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>place</term>
+ <listitem>
+ <para>
+ Place of this record. Defaults to 1, indicating 'Answer' section. Can also be 2, for Authority of 3 for Additional.
+ When using this rare feature, always emit records with 'Place' in ascending order. This field is usually not needed.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>qname</term>
+ <listitem>
+ <para>
+ qname of the answer, the 'name' of the record. Defaults to the name of the query, which is almost always correct except when
+ specifying additional records or rolling out a CNAME chain.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>qtype</term>
+ <listitem>
+ <para>
+ Currently the numerical qtype of the answer, defaulting to '1' which is an A record. '2' is an NS record, '5' a CNAME and '15' an MX record.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>ttl</term>
+ <listitem>
+ <para>
+ Time to live of a record. Defaults to 3600. Be sure not to specify differing TTLs within answers with an identical qname. While this
+ can be encoded in DNS, results may be undesired.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
</sect2>
</sect1>
<sect1 id="recursor-design-and-engineering">
PowerDNSLua::PowerDNSLua(const std::string& fname)
{
d_lua = lua_open();
+
+#ifndef LUA_VERSION_NUM
luaopen_base(d_lua);
luaopen_string(d_lua);
- lua_settop(d_lua, 0);
-#ifndef LUA_VERSION_NUM
if(lua_dofile(d_lua, fname.c_str()))
#else
+ luaL_openlibs(d_lua);
if(luaL_dofile(d_lua, fname.c_str()))
#endif
throw runtime_error(string("Error loading LUA file '")+fname+"': "+ string(lua_isstring(d_lua, -1) ? lua_tostring(d_lua, -1) : "unknown error"));
+
+ lua_settop(d_lua, 0);
lua_pushcfunction(d_lua, netmaskMatchLua);
lua_setglobal(d_lua, "matchnetmask");
bool ret=false;
if(!lua_isnil(d_lua, -1)) {
- value = lua_tonumber(d_lua, -1);
+ value = (uint32_t)lua_tonumber(d_lua, -1);
ret=true;
}
lua_pop(d_lua, 1);
lua_pushstring(d_lua, query.c_str() );
lua_pushnumber(d_lua, qtype.getCode() );
- lua_call(d_lua, 3, 2);
- res = lua_tonumber(d_lua, 1); // new rcode
+ if(lua_pcall(d_lua, 3, 2, 0)) { // error
+ string error=string("lua error: ")+lua_tostring(d_lua, -1);
+ lua_pop(d_lua, 1);
+ throw runtime_error(error);
+ return false;
+ }
+ res = (int)lua_tonumber(d_lua, 1); // new rcode
if(res < 0) {
// cerr << "handler did not handle"<<endl;
lua_pop(d_lua, 2);
return false;
}
- else
- cerr<<"res = "<<res<<endl;
/* get the result */
DNSResourceRecord rr;