Lua actions in rulesΒΆ

dnsdist comes with a lot of built-in selectors and actions, but it is also possible to write custom selectors and actions in Lua. Note that Lua is usually slower than built-in options written in C++, although the FFI and per-thread FFI options can be quite competitive, as explained in tuning guide.

To write a custom selector in Lua, one can do:

function lua_selector(dq)
  return dq.qtype == DNSQType.A
end
addAction(LuaRule(lua_selector), DropAction())

And for a custom action:

function lua_route_tc_to_abuse_pool(dq)
  local tc = dq.dh:getTC()
  -- The TC (truncated) bit should not be set in a query
  if tc then
    return DNSAction.Pool, "abuse" -- send to abuse pool
  end
  -- otherwise we keep processing subsequent rules, if any
  return DNSAction.None
end
addAction(AllRule(), LuaAction(lua_route_tc_to_abuse_pool))

If the YAML configuration is used, there are three different ways of calling a Lua function. The first option is to declare the Lua function in a global Lua file that will loaded before the YAML configuration is parsed. This is done by creating a Lua file with the exact same name as the YAML configuration one, but with a .lua extension. See YAML configuration reference for more information. For example, creating a file named /etc/dnsdist/dnsdist.lua containing:

function lua_route_tc_to_abuse_pool(dq)
  local tc = dq.dh:getTC()
  -- The TC (truncated) bit should not be set in a query
  if tc then
    return DNSAction.Pool, "abuse" -- send to abuse pool
  end
  -- otherwise we keep processing subsequent rules, if any
  return DNSAction.None
end

it is now possible to call this function from the YAML configuration at /etc/dnsdist/dnsdist.yml

query_rules:
  - name: "route truncated queries for powerdns.com to the abuse pool"
    selector:
      type: "QNameSet"
      qnames:
        - "powerdns.com."
    action:
      type: "Lua"
      function_name: "lua_route_tc_to_abuse_pool"

A second option is to declare the Lua code inline in the YAML configuration file, which requires returning a Lua function, which does not need to be named:

query_rules:
  - name: "route truncated queries for powerdns.com to the abuse pool"
    selector:
      type: "QNameSet"
      qnames:
        - "powerdns.com."
    action:
      type: "Lua"
      function_code: |
        return function lua_route_tc_to_abuse_pool(dq)
          local tc = dq.dh:getTC()
          -- The TC (truncated) bit should not be set in a query
          if tc then
            return DNSAction.Pool, "abuse" -- send to abuse pool
          end
          -- otherwise we keep processing subsequent rules, if any
          return DNSAction.None
        end

Finally the third option is to declare the Lua code in a separate file which is referenced from the YAML configuration. The separate file has to return a Lua function, as in the previous case:

query_rules:
  - name: "route truncated queries for powerdns.com to the abuse pool"
    selector:
      type: "QNameSet"
      qnames:
        - "powerdns.com."
    action:
      type: "Lua"
      function_file: "/etc/dnsdist/truncated-to-pool-abuse.lua"

where the /etc/dnsdist/truncated-to-pool-abuse.lua file contains:

return function(dq)
  local tc = dq.dh:getTC()
  -- The TC (truncated) bit should not be set in a query
  if tc then
    return DNSAction.Pool, "abuse" -- send to abuse pool
  end
  -- otherwise we keep processing subsequent rules, if any
  return DNSAction.None
end