]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Move each Lua function lambda to its own toplevel function.
authorMiod Vallat <miod.vallat@powerdns.com>
Fri, 28 Feb 2025 07:37:57 +0000 (08:37 +0100)
committerMiod Vallat <miod.vallat@powerdns.com>
Fri, 28 Feb 2025 07:45:20 +0000 (08:45 +0100)
This does not change anything, but reduces indent and makes the code
easier to read. No functional change yet.

pdns/lua-record.cc

index ca0aa874cabfff71b497e67898cefbab23ef10f8..ceeb826b4f063352e47331ba48c0a146785d4cea 100644 (file)
@@ -914,619 +914,804 @@ static vector<string> genericIfUp(const boost::variant<iplist_t, ipunitlist_t>&
   return convComboAddressListToString(res);
 }
 
-static void setupLuaRecords(LuaContext& lua) // NOLINT(readability-function-cognitive-complexity)
+// Lua functions available to the user
+
+static string lua_latlon()
 {
-  lua.writeFunction("latlon", []() {
-      double lat = 0, lon = 0;
-      getLatLon(s_lua_record_ctx->bestwho.toString(), lat, lon);
-      return std::to_string(lat)+" "+std::to_string(lon);
-    });
-  lua.writeFunction("latlonloc", []() {
-      string loc;
-      getLatLon(s_lua_record_ctx->bestwho.toString(), loc);
-      return loc;
-  });
-  lua.writeFunction("closestMagic", []() {
-      vector<ComboAddress> candidates;
-      // Getting something like 192-0-2-1.192-0-2-2.198-51-100-1.example.org
-      for(auto l : s_lua_record_ctx->qname.getRawLabels()) {
-        std::replace(l.begin(), l.end(), '-', '.');
-        try {
-          candidates.emplace_back(l);
-        } catch (const PDNSException& e) {
-          // no need to continue as we most likely reached the end of the ip list
-          break ;
-        }
-      }
-      return pickclosest(s_lua_record_ctx->bestwho, candidates).toString();
-    });
-  lua.writeFunction("latlonMagic", [](){
-      auto labels= s_lua_record_ctx->qname.getRawLabels();
-      if(labels.size()<4)
-        return std::string("unknown");
-      double lat = 0, lon = 0;
-      getLatLon(labels[3]+"."+labels[2]+"."+labels[1]+"."+labels[0], lat, lon);
-      return std::to_string(lat)+" "+std::to_string(lon);
-    });
+  double lat = 0, lon = 0;
+  getLatLon(s_lua_record_ctx->bestwho.toString(), lat, lon);
+  return std::to_string(lat)+" "+std::to_string(lon);
+}
 
+static string lua_latlonloc()
+{
+  string loc;
+  getLatLon(s_lua_record_ctx->bestwho.toString(), loc);
+  return loc;
+}
 
-  lua.writeFunction("createReverse", [](string format, boost::optional<std::unordered_map<string,string>> e){
-      try {
-        auto labels = s_lua_record_ctx->qname.getRawLabels();
-        if(labels.size()<4)
-          return std::string("unknown");
-
-        vector<ComboAddress> candidates;
-
-        // so, query comes in for 4.3.2.1.in-addr.arpa, zone is called 2.1.in-addr.arpa
-        // e["1.2.3.4"]="bert.powerdns.com" then provides an exception
-        if(e) {
-          ComboAddress req(labels[3]+"."+labels[2]+"."+labels[1]+"."+labels[0], 0);
-          const auto& uom = *e;
-          for(const auto& c : uom)
-            if(ComboAddress(c.first, 0) == req)
-              return c.second;
-        }
-        boost::format fmt(format);
-        fmt.exceptions( boost::io::all_error_bits ^ ( boost::io::too_many_args_bit | boost::io::too_few_args_bit )  );
-        fmt % labels[3] % labels[2] % labels[1] % labels[0];
+static string lua_closestMagic()
+{
+  vector<ComboAddress> candidates;
+  // Getting something like 192-0-2-1.192-0-2-2.198-51-100-1.example.org
+  for(auto l : s_lua_record_ctx->qname.getRawLabels()) {
+    std::replace(l.begin(), l.end(), '-', '.');
+    try {
+      candidates.emplace_back(l);
+    } catch (const PDNSException& e) {
+      // no need to continue as we most likely reached the end of the ip list
+      break ;
+    }
+  }
+  return pickclosest(s_lua_record_ctx->bestwho, candidates).toString();
+}
 
-        fmt % (labels[3]+"-"+labels[2]+"-"+labels[1]+"-"+labels[0]);
+static string lua_latlonMagic()
+{
+   auto labels= s_lua_record_ctx->qname.getRawLabels();
+   if(labels.size()<4)
+     return std::string("unknown");
+   double lat = 0, lon = 0;
+   getLatLon(labels[3]+"."+labels[2]+"."+labels[1]+"."+labels[0], lat, lon);
+   return std::to_string(lat)+" "+std::to_string(lon);
+}
 
-        boost::format fmt2("%02x%02x%02x%02x");
-        for(int i=3; i>=0; --i)
-          fmt2 % atoi(labels[i].c_str());
+static string lua_createReverse(string format, boost::optional<std::unordered_map<string,string>> e)
+{
+  try {
+    auto labels = s_lua_record_ctx->qname.getRawLabels();
+    if(labels.size()<4)
+      return std::string("unknown");
 
-        fmt % (fmt2.str());
+    vector<ComboAddress> candidates;
 
-        return fmt.str();
-      }
-      catch(std::exception& ex) {
-        g_log<<Logger::Error<<"error: "<<ex.what()<<endl;
-      }
-      return std::string("error");
-    });
-  lua.writeFunction("createForward", []() {
-      static string allZerosIP{"0.0.0.0"};
-      try {
-        DNSName record_name{s_lua_record_ctx->zone_record.dr.d_name};
-        if (!record_name.isWildcard()) {
-          return allZerosIP;
-        }
-        record_name.chopOff();
-        DNSName rel{s_lua_record_ctx->qname.makeRelative(record_name)};
-
-        // parts is something like ["1", "2", "3", "4", "static"] or
-        // ["1", "2", "3", "4"] or ["ip40414243", "ip-addresses", ...]
-        auto parts = rel.getRawLabels();
-        // Yes, this still breaks if an 1-2-3-4.XXXX is nested too deeply...
-        if (parts.size() >= 4) {
-          ComboAddress address(parts[0]+"."+parts[1]+"."+parts[2]+"."+parts[3]);
-          return address.toString();
-        }
-       if (!parts.empty()) {
-          auto& input = parts.at(0);
+    // so, query comes in for 4.3.2.1.in-addr.arpa, zone is called 2.1.in-addr.arpa
+    // e["1.2.3.4"]="bert.powerdns.com" then provides an exception
+    if(e) {
+      ComboAddress req(labels[3]+"."+labels[2]+"."+labels[1]+"."+labels[0], 0);
+      const auto& uom = *e;
+      for(const auto& c : uom)
+        if(ComboAddress(c.first, 0) == req)
+          return c.second;
+    }
+    boost::format fmt(format);
+    fmt.exceptions( boost::io::all_error_bits ^ ( boost::io::too_many_args_bit | boost::io::too_few_args_bit )  );
+    fmt % labels[3] % labels[2] % labels[1] % labels[0];
 
-          // allow a word without - in front, as long as it does not contain anything that could be a number
-          size_t nonhexprefix = strcspn(input.c_str(), "0123456789abcdefABCDEF");
-          if (nonhexprefix > 0) {
-            input = input.substr(nonhexprefix);
-          }
+    fmt % (labels[3]+"-"+labels[2]+"-"+labels[1]+"-"+labels[0]);
 
-          // either hex string, or 12-13-14-15
-          vector<string> ip_parts;
-
-          stringtok(ip_parts, input, "-");
-          if (ip_parts.size() >= 4) {
-            // 1-2-3-4 with any prefix (e.g. ip-foo-bar-1-2-3-4)
-            string ret;
-            for (size_t index=4; index > 0; index--) {
-              auto octet = ip_parts.at(ip_parts.size() - index);
-              auto octetVal = std::stol(octet); // may throw
-              if (octetVal >= 0 && octetVal <= 255) {
-                ret += octet + ".";
-              } else {
-                return allZerosIP;
-              }
-            }
-            ret.resize(ret.size() - 1); // remove trailing dot after last octet
-            return ret;
-          }
-          if (input.length() >= 8) {
-            auto last8 = input.substr(input.length()-8);
-            unsigned int part1{0};
-            unsigned int part2{0};
-            unsigned int part3{0};
-            unsigned int part4{0};
-            if (sscanf(last8.c_str(), "%02x%02x%02x%02x", &part1, &part2, &part3, &part4) == 4) {
-              ComboAddress address(std::to_string(part1) + "." + std::to_string(part2) + "." + std::to_string(part3) + "." + std::to_string(part4));
-              return address.toString();
-            }
-          }
-        }
-        return allZerosIP;
-      } catch (const PDNSException &e) {
-        return allZerosIP;
-      }
-    });
+    boost::format fmt2("%02x%02x%02x%02x");
+    for(int i=3; i>=0; --i)
+      fmt2 % atoi(labels[i].c_str());
 
-  lua.writeFunction("createForward6", []() {
-      static string allZerosIP{"::"};
-      try {
-        DNSName record_name{s_lua_record_ctx->zone_record.dr.d_name};
-        if (!record_name.isWildcard()) {
-          return allZerosIP;
-        }
-        record_name.chopOff();
-        DNSName rel{s_lua_record_ctx->qname.makeRelative(record_name)};
-
-        auto parts = rel.getRawLabels();
-        if (parts.size() == 8) {
-          string tot;
-          for (int chunk = 0; chunk < 8; ++chunk) {
-            if (chunk != 0) {
-              tot.append(1, ':');
-             }
-            tot += parts.at(chunk);
-          }
-          ComboAddress address(tot);
-          return address.toString();
-        }
-        if (parts.size() == 1) {
-          if (parts[0].find('-') != std::string::npos) {
-            std::replace(parts[0].begin(), parts[0].end(), '-', ':');
-            ComboAddress address(parts[0]);
-            return address.toString();
-          }
-          if (parts[0].size() >= 32) {
-            auto ippart = parts[0].substr(parts[0].size()-32);
-            auto fulladdress =
-              ippart.substr(0, 4) + ":" +
-              ippart.substr(4, 4) + ":" +
-              ippart.substr(8, 4) + ":" +
-              ippart.substr(12, 4) + ":" +
-              ippart.substr(16, 4) + ":" +
-              ippart.substr(20, 4) + ":" +
-              ippart.substr(24, 4) + ":" +
-              ippart.substr(28, 4);
-
-            ComboAddress address(fulladdress);
-            return address.toString();
-          }
-        }
-        return allZerosIP;
-      } catch (const PDNSException &e) {
-        return allZerosIP;
+    fmt % (fmt2.str());
+
+    return fmt.str();
+  }
+  catch(std::exception& ex) {
+    g_log<<Logger::Error<<"error: "<<ex.what()<<endl;
+  }
+  return std::string("error");
+}
+
+static string lua_createForward()
+{
+  static string allZerosIP{"0.0.0.0"};
+  try {
+    DNSName record_name{s_lua_record_ctx->zone_record.dr.d_name};
+    if (!record_name.isWildcard()) {
+      return allZerosIP;
+    }
+    record_name.chopOff();
+    DNSName rel{s_lua_record_ctx->qname.makeRelative(record_name)};
+
+    // parts is something like ["1", "2", "3", "4", "static"] or
+    // ["1", "2", "3", "4"] or ["ip40414243", "ip-addresses", ...]
+    auto parts = rel.getRawLabels();
+    // Yes, this still breaks if an 1-2-3-4.XXXX is nested too deeply...
+    if (parts.size() >= 4) {
+      ComboAddress address(parts[0]+"."+parts[1]+"."+parts[2]+"."+parts[3]);
+      return address.toString();
+    }
+    if (!parts.empty()) {
+      auto& input = parts.at(0);
+
+      // allow a word without - in front, as long as it does not contain anything that could be a number
+      size_t nonhexprefix = strcspn(input.c_str(), "0123456789abcdefABCDEF");
+      if (nonhexprefix > 0) {
+        input = input.substr(nonhexprefix);
       }
-    });
-  lua.writeFunction("createReverse6", [](const string &format, boost::optional<std::unordered_map<string,string>> excp){
-      vector<ComboAddress> candidates;
 
-      try {
-        auto labels= s_lua_record_ctx->qname.getRawLabels();
-        if (labels.size()<32) {
-          return std::string("unknown");
-       }
-        boost::format fmt(format);
-        fmt.exceptions( boost::io::all_error_bits ^ ( boost::io::too_many_args_bit | boost::io::too_few_args_bit )  );
-
-
-        string together;
-        vector<string> quads;
-        for (int chunk = 0; chunk < 8; ++chunk) {
-          if (chunk != 0) {
-            together += ":";
-         }
-          string lquad;
-          for (int quartet = 0; quartet < 4; ++quartet) {
-            lquad.append(1, labels[31 - chunk * 4 - quartet][0]);
-            together += labels[31 - chunk * 4 - quartet][0];
+      // either hex string, or 12-13-14-15
+      vector<string> ip_parts;
+
+      stringtok(ip_parts, input, "-");
+      if (ip_parts.size() >= 4) {
+        // 1-2-3-4 with any prefix (e.g. ip-foo-bar-1-2-3-4)
+        string ret;
+        for (size_t index=4; index > 0; index--) {
+          auto octet = ip_parts.at(ip_parts.size() - index);
+          auto octetVal = std::stol(octet); // may throw
+          if (octetVal >= 0 && octetVal <= 255) {
+            ret += octet + ".";
+          } else {
+            return allZerosIP;
           }
-          quads.push_back(lquad);
         }
-       ComboAddress ip6(together,0);
-
-       if (excp) {
-          auto& addrs=*excp;
-          for(const auto& addr: addrs) {
-            // this makes sure we catch all forms of the address
-            if (ComboAddress(addr.first, 0) == ip6) {
-              return addr.second;
-           }
-          }
+        ret.resize(ret.size() - 1); // remove trailing dot after last octet
+        return ret;
+      }
+      if (input.length() >= 8) {
+        auto last8 = input.substr(input.length()-8);
+        unsigned int part1{0};
+        unsigned int part2{0};
+        unsigned int part3{0};
+        unsigned int part4{0};
+        if (sscanf(last8.c_str(), "%02x%02x%02x%02x", &part1, &part2, &part3, &part4) == 4) {
+          ComboAddress address(std::to_string(part1) + "." + std::to_string(part2) + "." + std::to_string(part3) + "." + std::to_string(part4));
+          return address.toString();
         }
+      }
+    }
+    return allZerosIP;
+  } catch (const PDNSException &e) {
+    return allZerosIP;
+  }
+}
 
-        string dashed=ip6.toString();
-        std::replace(dashed.begin(), dashed.end(), ':', '-');
+static string lua_createForward6()
+{
+   static string allZerosIP{"::"};
+   try {
+     DNSName record_name{s_lua_record_ctx->zone_record.dr.d_name};
+     if (!record_name.isWildcard()) {
+       return allZerosIP;
+     }
+     record_name.chopOff();
+     DNSName rel{s_lua_record_ctx->qname.makeRelative(record_name)};
+
+     auto parts = rel.getRawLabels();
+     if (parts.size() == 8) {
+       string tot;
+       for (int chunk = 0; chunk < 8; ++chunk) {
+         if (chunk != 0) {
+           tot.append(1, ':');
+         }
+        tot += parts.at(chunk);
+      }
+      ComboAddress address(tot);
+      return address.toString();
+    }
+    if (parts.size() == 1) {
+      if (parts[0].find('-') != std::string::npos) {
+        std::replace(parts[0].begin(), parts[0].end(), '-', ':');
+        ComboAddress address(parts[0]);
+        return address.toString();
+      }
+      if (parts[0].size() >= 32) {
+        auto ippart = parts[0].substr(parts[0].size()-32);
+        auto fulladdress =
+          ippart.substr(0, 4) + ":" +
+          ippart.substr(4, 4) + ":" +
+          ippart.substr(8, 4) + ":" +
+          ippart.substr(12, 4) + ":" +
+          ippart.substr(16, 4) + ":" +
+          ippart.substr(20, 4) + ":" +
+          ippart.substr(24, 4) + ":" +
+          ippart.substr(28, 4);
+
+        ComboAddress address(fulladdress);
+        return address.toString();
+      }
+    }
+    return allZerosIP;
+  } catch (const PDNSException &e) {
+    return allZerosIP;
+  }
+}
 
-        // https://github.com/PowerDNS/pdns/issues/7524
-        if (boost::ends_with(dashed, "-")) {
-          // "a--a-" -> "a--a-0"
-          dashed.push_back('0');
-        }
-        if (boost::starts_with(dashed, "-") || dashed.compare(2, 2, "--") == 0) {
-          // "-a--a" -> "0-a--a"               "aa--a" -> "0aa--a"
-          dashed.insert(0, "0");
-        }
+static string lua_createReverse6(const string &format, boost::optional<std::unordered_map<string,string>> excp)
+{
+  vector<ComboAddress> candidates;
 
-        for (int byte = 31; byte >= 0; --byte) {
-          fmt % labels[byte];
-       }
-        fmt % dashed;
+  try {
+    auto labels= s_lua_record_ctx->qname.getRawLabels();
+    if (labels.size()<32) {
+      return std::string("unknown");
+    }
 
-        for(const auto& lquad : quads) {
-          fmt % lquad;
-       }
+    boost::format fmt(format);
+    fmt.exceptions( boost::io::all_error_bits ^ ( boost::io::too_many_args_bit | boost::io::too_few_args_bit )  );
 
-        return fmt.str();
+    string together;
+    vector<string> quads;
+    for (int chunk = 0; chunk < 8; ++chunk) {
+      if (chunk != 0) {
+        together += ":";
       }
-      catch(std::exception& ex) {
-        g_log<<Logger::Error<<"Lua record exception: "<<ex.what()<<endl;
+      string lquad;
+      for (int quartet = 0; quartet < 4; ++quartet) {
+        lquad.append(1, labels[31 - chunk * 4 - quartet][0]);
+        together += labels[31 - chunk * 4 - quartet][0];
       }
-      catch(PDNSException& ex) {
-        g_log<<Logger::Error<<"Lua record exception: "<<ex.reason<<endl;
+      quads.push_back(lquad);
+    }
+    ComboAddress ip6(together,0);
+
+    if (excp) {
+      auto& addrs=*excp;
+      for(const auto& addr: addrs) {
+        // this makes sure we catch all forms of the address
+        if (ComboAddress(addr.first, 0) == ip6) {
+          return addr.second;
+        }
       }
-      return std::string("unknown");
-    });
+    }
 
-  lua.writeFunction("filterForward", [](const string& address, NetmaskGroup& nmg, boost::optional<string> fallback) -> vector<string> {
-      ComboAddress ca(address);
+    string dashed=ip6.toString();
+    std::replace(dashed.begin(), dashed.end(), ':', '-');
 
-      if (nmg.match(ComboAddress(address))) {
-        return {address};
-      } else {
-        if (fallback) {
-          if (fallback->empty()) {
-            // if fallback is an empty string, return an empty array
-            return {};
-          }
-          return {*fallback};
-        }
+    // https://github.com/PowerDNS/pdns/issues/7524
+    if (boost::ends_with(dashed, "-")) {
+      // "a--a-" -> "a--a-0"
+      dashed.push_back('0');
+    }
+    if (boost::starts_with(dashed, "-") || dashed.compare(2, 2, "--") == 0) {
+      // "-a--a" -> "0-a--a"               "aa--a" -> "0aa--a"
+      dashed.insert(0, "0");
+    }
 
-        if (ca.isIPv4()) {
-          return {string("0.0.0.0")};
-        } else {
-          return {string("::")};
-        }
-      }
-    });
+    for (int byte = 31; byte >= 0; --byte) {
+      fmt % labels[byte];
+    }
+    fmt % dashed;
 
-  /*
-   * Simplistic test to see if an IP address listens on a certain port
-   * Will return a single IP address from the set of available IP addresses. If
-   * no IP address is available, will return a random element of the set of
-   * addresses supplied for testing.
-   *
-   * @example ifportup(443, { '1.2.3.4', '5.4.3.2' })"
-   */
-  lua.writeFunction("ifportup", [](int port, const boost::variant<iplist_t, ipunitlist_t>& ips, const boost::optional<std::unordered_map<string,string>> options) {
-    port = std::max(port, 0);
-    port = std::min(port, static_cast<int>(std::numeric_limits<uint16_t>::max()));
+    for(const auto& lquad : quads) {
+      fmt % lquad;
+    }
 
-    auto checker = [](const ComboAddress& addr, const opts_t& opts) {
-      return g_up.isUp(addr, opts);
-    };
-    return genericIfUp(ips, options, checker, port);
-  });
+    return fmt.str();
+  }
+  catch(std::exception& ex) {
+    g_log<<Logger::Error<<"Lua record exception: "<<ex.what()<<endl;
+  }
+  catch(PDNSException& ex) {
+    g_log<<Logger::Error<<"Lua record exception: "<<ex.reason<<endl;
+  }
+  return std::string("unknown");
+}
 
-  lua.writeFunction("ifurlextup", [](const vector<pair<int, opts_t> >& ipurls, boost::optional<opts_t> options) {
-      vector<ComboAddress> candidates;
-      opts_t opts;
-      if(options)
-        opts = *options;
-
-      ComboAddress ca_unspec;
-      ca_unspec.sin4.sin_family=AF_UNSPEC;
-
-      // ipurls: { { ["192.0.2.1"] = "https://example.com", ["192.0.2.2"] = "https://example.com/404" } }
-      for (const auto& [count, unitmap] : ipurls) {
-        // unitmap: 1 = { ["192.0.2.1"] = "https://example.com", ["192.0.2.2"] = "https://example.com/404" }
-        vector<ComboAddress> available;
-
-        for (const auto& [ipStr, url] : unitmap) {
-          // unit: ["192.0.2.1"] = "https://example.com"
-          ComboAddress ip(ipStr);
-          candidates.push_back(ip);
-          if (g_up.isUp(ca_unspec, url, opts)) {
-            available.push_back(ip);
-          }
-        }
-        if(!available.empty()) {
-          vector<ComboAddress> res = useSelector(getOptionValue(options, "selector", "random"), s_lua_record_ctx->bestwho, available);
-          return convComboAddressListToString(res);
-        }
+static vector<string> lua_filterForward(const string& address, NetmaskGroup& nmg, boost::optional<string> fallback)
+{
+  ComboAddress ca(address);
+
+  if (nmg.match(ComboAddress(address))) {
+    return {address};
+  } else {
+    if (fallback) {
+      if (fallback->empty()) {
+        // if fallback is an empty string, return an empty array
+        return {};
       }
+      return {*fallback};
+    }
 
-      // All units down, apply backupSelector on all candidates
-      vector<ComboAddress> res = useSelector(getOptionValue(options, "backupSelector", "random"), s_lua_record_ctx->bestwho, candidates);
+    if (ca.isIPv4()) {
+      return {string("0.0.0.0")};
+    } else {
+      return {string("::")};
+    }
+  }
+}
+
+/*
+ * Simplistic test to see if an IP address listens on a certain port
+ * Will return a single IP address from the set of available IP addresses. If
+ * no IP address is available, will return a random element of the set of
+ * addresses supplied for testing.
+ *
+ * @example ifportup(443, { '1.2.3.4', '5.4.3.2' })"
+ */
+static vector<string> lua_ifportup(int port, const boost::variant<iplist_t, ipunitlist_t>& ips, const boost::optional<std::unordered_map<string,string>> options)
+{
+  port = std::max(port, 0);
+  port = std::min(port, static_cast<int>(std::numeric_limits<uint16_t>::max()));
+
+  auto checker = [](const ComboAddress& addr, const opts_t& opts) {
+    return g_up.isUp(addr, opts);
+  };
+  return genericIfUp(ips, options, checker, port);
+}
+
+static vector<string> lua_ifurlextup(const vector<pair<int, opts_t> >& ipurls, boost::optional<opts_t> options)
+{
+  vector<ComboAddress> candidates;
+  opts_t opts;
+  if(options)
+    opts = *options;
+
+  ComboAddress ca_unspec;
+  ca_unspec.sin4.sin_family=AF_UNSPEC;
+
+  // ipurls: { { ["192.0.2.1"] = "https://example.com", ["192.0.2.2"] = "https://example.com/404" } }
+  for (const auto& [count, unitmap] : ipurls) {
+    // unitmap: 1 = { ["192.0.2.1"] = "https://example.com", ["192.0.2.2"] = "https://example.com/404" }
+    vector<ComboAddress> available;
+
+    for (const auto& [ipStr, url] : unitmap) {
+      // unit: ["192.0.2.1"] = "https://example.com"
+      ComboAddress ip(ipStr);
+      candidates.push_back(ip);
+      if (g_up.isUp(ca_unspec, url, opts)) {
+        available.push_back(ip);
+      }
+    }
+    if(!available.empty()) {
+      vector<ComboAddress> res = useSelector(getOptionValue(options, "selector", "random"), s_lua_record_ctx->bestwho, available);
       return convComboAddressListToString(res);
+    }
+  }
+
+  // All units down, apply backupSelector on all candidates
+  vector<ComboAddress> res = useSelector(getOptionValue(options, "backupSelector", "random"), s_lua_record_ctx->bestwho, candidates);
+  return convComboAddressListToString(res);
+}
+
+static vector<string> lua_ifurlup(const std::string& url, const boost::variant<iplist_t, ipunitlist_t>& ips, boost::optional<opts_t> options)
+{
+  auto checker = [&url](const ComboAddress& addr, const opts_t& opts) {
+    return g_up.isUp(addr, url, opts);
+  };
+  return genericIfUp(ips, options, checker);
+}
+
+/*
+ * Returns a random IP address from the supplied list
+ * @example pickrandom({ '1.2.3.4', '5.4.3.2' })"
+ */
+static string lua_pickrandom(const iplist_t& ips)
+{
+  vector<string> items = convStringList(ips);
+  return pickRandom<string>(items);
+}
+
+/*
+ * Based on the hash of `bestwho`, returns an IP address from the list
+ * supplied, weighted according to the results of isUp calls.
+ * @example pickselfweighted('http://example.com/weight', { "192.0.2.20", "203.0.113.4", "203.0.113.2" })
+ */
+static string lua_pickselfweighted(const std::string& url, const iplist_t& ips, boost::optional<opts_t> options)
+{
+  vector< pair<int, ComboAddress> > items;
+  opts_t opts;
+  if(options) {
+    opts = *options;
+  }
+
+  items.reserve(ips.capacity());
+  bool available = false;
+
+  vector<ComboAddress> conv = convComboAddressList(ips);
+  for (auto& entry : conv) {
+    int weight = 0;
+    weight = g_up.isUp(entry, url, opts);
+    if(weight>0) {
+      available = true;
+    }
+    items.emplace_back(weight, entry);
+  }
+  if(available) {
+    return pickWeightedHashed<ComboAddress>(s_lua_record_ctx->bestwho, items).toString();
+  }
+
+  // All units down, apply backupSelector on all candidates
+  return pickWeightedRandom<ComboAddress>(items).toString();
+}
+
+static vector<string> lua_pickrandomsample(int n, const iplist_t& ips)
+{
+  vector<string> items = convStringList(ips);
+  return pickRandomSample<string>(n, items);
+}
+
+static string lua_pickhashed(const iplist_t& ips)
+{
+  vector<string> items = convStringList(ips);
+  return pickHashed<string>(s_lua_record_ctx->bestwho, items);
+}
+
+/*
+ * Returns a random IP address from the supplied list, as weighted by the
+ * various ``weight`` parameters
+ * @example pickwrandom({ {100, '1.2.3.4'}, {50, '5.4.3.2'}, {1, '192.168.1.0'} })
+ */
+static string lua_pickwrandom(std::unordered_map<int, wiplist_t> ips)
+{
+  vector< pair<int, string> > items = convIntStringPairList(ips);
+  return pickWeightedRandom<string>(items);
+}
+
+/*
+ * Based on the hash of `bestwho`, returns an IP address from the list
+ * supplied, as weighted by the various `weight` parameters
+ * @example pickwhashed({ {15, '1.2.3.4'}, {50, '5.4.3.2'} })
+ */
+static string lua_pickwhashed(std::unordered_map<int, wiplist_t > ips)
+{
+  vector< pair<int, string> > items;
+
+  items.reserve(ips.size());
+  for (auto& entry : ips) {
+    items.emplace_back(atoi(entry.second[1].c_str()), entry.second[2]);
+  }
+
+  return pickWeightedHashed<string>(s_lua_record_ctx->bestwho, items);
+}
+
+/*
+ * Based on the hash of the record name, return an IP address from the list
+ * supplied, as weighted by the various `weight` parameters
+ * @example picknamehashed({ {15, '1.2.3.4'}, {50, '5.4.3.2'} })
+ */
+static string lua_picknamehashed(std::unordered_map<int, wiplist_t > ips)
+{
+  vector< pair<int, string> > items;
+
+  items.reserve(ips.size());
+  for(auto& i : ips)
+  {
+    items.emplace_back(atoi(i.second[1].c_str()), i.second[2]);
+  }
+
+  return pickWeightedNameHashed<string>(s_lua_record_ctx->qname, items);
+}
+
+/*
+ * Based on the hash of `bestwho`, returns an IP address from the list
+ * supplied, as weighted by the various `weight` parameters and distributed consistently
+ * @example pickchashed({ {15, '1.2.3.4'}, {50, '5.4.3.2'} })
+ */
+static string lua_pickchashed(const std::unordered_map<int, wiplist_t>& ips)
+{
+  std::vector<std::pair<int, std::string>> items;
+
+  items.reserve(ips.size());
+  for (const auto& entry : ips) {
+    items.emplace_back(atoi(entry.second.at(1).c_str()), entry.second.at(2));
+  }
+
+  return pickConsistentWeightedHashed(s_lua_record_ctx->bestwho, items);
+}
+
+static string lua_pickclosest(const iplist_t& ips)
+{
+  vector<ComboAddress> conv = convComboAddressList(ips);
+
+  return pickclosest(s_lua_record_ctx->bestwho, conv).toString();
+}
+
+static string lua_report(string /* event */, boost::optional<string> /* line */)
+{
+  throw std::runtime_error("Script took too long");
+}
+
+static string lua_geoiplookup(const string &ip, const GeoIPInterface::GeoIPQueryAttribute attr)
+{
+  return getGeo(ip, attr);
+}
+
+typedef const boost::variant<string,vector<pair<int,string> > > combovar_t;
+
+static bool lua_asnum(const combovar_t& asns)
+{
+  string res=getGeo(s_lua_record_ctx->bestwho.toString(), GeoIPInterface::ASn);
+  return doCompare(asns, res, [](const std::string& a, const std::string& b) {
+      return !strcasecmp(a.c_str(), b.c_str());
     });
+}
 
-  lua.writeFunction("ifurlup", [](const std::string& url,
-                                          const boost::variant<iplist_t, ipunitlist_t>& ips,
-                                          boost::optional<opts_t> options) {
+static bool lua_continent(const combovar_t& continent)
+{
+  string res=getGeo(s_lua_record_ctx->bestwho.toString(), GeoIPInterface::Continent);
+  return doCompare(continent, res, [](const std::string& a, const std::string& b) {
+      return !strcasecmp(a.c_str(), b.c_str());
+    });
+}
 
-    auto checker = [&url](const ComboAddress& addr, const opts_t& opts) {
-        return g_up.isUp(addr, url, opts);
-      };
-      return genericIfUp(ips, options, checker);
+static string lua_continentCode()
+{
+  string unknown("unknown");
+  string res = getGeo(s_lua_record_ctx->bestwho.toString(), GeoIPInterface::Continent);
+  if ( res == unknown ) {
+   return std::string("--");
+  }
+  return res;
+}
+
+static bool lua_country(const combovar_t& var)
+{
+  string res = getGeo(s_lua_record_ctx->bestwho.toString(), GeoIPInterface::Country2);
+  return doCompare(var, res, [](const std::string& a, const std::string& b) {
+      return !strcasecmp(a.c_str(), b.c_str());
     });
-  /*
-   * Returns a random IP address from the supplied list
-   * @example pickrandom({ '1.2.3.4', '5.4.3.2' })"
-   */
-  lua.writeFunction("pickrandom", [](const iplist_t& ips) {
-      vector<string> items = convStringList(ips);
-      return pickRandom<string>(items);
+
+}
+
+static string lua_countryCode()
+{
+  string unknown("unknown");
+  string res = getGeo(s_lua_record_ctx->bestwho.toString(), GeoIPInterface::Country2);
+  if ( res == unknown ) {
+   return std::string("--");
+  }
+  return res;
+}
+
+static bool lua_region(const combovar_t& var)
+{
+  string res = getGeo(s_lua_record_ctx->bestwho.toString(), GeoIPInterface::Region);
+  return doCompare(var, res, [](const std::string& a, const std::string& b) {
+      return !strcasecmp(a.c_str(), b.c_str());
     });
 
-  /*
-   * Based on the hash of `bestwho`, returns an IP address from the list
-   * supplied, weighted according to the results of isUp calls.
-   * @example pickselfweighted('http://example.com/weight', { "192.0.2.20", "203.0.113.4", "203.0.113.2" })
-   */
-  lua.writeFunction("pickselfweighted", [](const std::string& url,
-                                             const iplist_t& ips,
-                                             boost::optional<opts_t> options) {
-      vector< pair<int, ComboAddress> > items;
-      opts_t opts;
-      if(options) {
-        opts = *options;
-      }
+}
+
+static string lua_regionCode()
+{
+  string unknown("unknown");
+  string res = getGeo(s_lua_record_ctx->bestwho.toString(), GeoIPInterface::Region);
+  if ( res == unknown ) {
+   return std::string("--");
+  }
+  return res;
+}
 
-      items.reserve(ips.capacity());
-      bool available = false;
+static bool lua_netmask(const iplist_t& ips)
+{
+  for(const auto& i :ips) {
+    Netmask nm(i.second);
+    if(nm.match(s_lua_record_ctx->bestwho))
+      return true;
+  }
+  return false;
+}
 
-      vector<ComboAddress> conv = convComboAddressList(ips);
-      for (auto& entry : conv) {
-        int weight = 0;
-        weight = g_up.isUp(entry, url, opts);
-        if(weight>0) {
-          available = true;
+/* {
+     {
+      {'192.168.0.0/16', '10.0.0.0/8'},
+      {'192.168.20.20', '192.168.20.21'}
+     },
+     {
+      {'0.0.0.0/0'}, {'192.0.2.1'}
+     }
+   }
+*/
+static string lua_view(const vector<pair<int, vector<pair<int, iplist_t> > > >& in)
+{
+  for(const auto& rule : in) {
+    const auto& netmasks=rule.second[0].second;
+    const auto& destinations=rule.second[1].second;
+    for(const auto& nmpair : netmasks) {
+      Netmask nm(nmpair.second);
+      if(nm.match(s_lua_record_ctx->bestwho)) {
+        if (destinations.empty()) {
+          throw std::invalid_argument("The IP list cannot be empty (for netmask " + nm.toString() + ")");
         }
-        items.emplace_back(weight, entry);
-      }
-      if(available) {
-        return pickWeightedHashed<ComboAddress>(s_lua_record_ctx->bestwho, items).toString();
+        return destinations[dns_random(destinations.size())].second;
       }
+    }
+  }
+  return std::string();
+}
 
-      // All units down, apply backupSelector on all candidates
-      return pickWeightedRandom<ComboAddress>(items).toString();
+static vector<string> lua_all(const vector< pair<int,string> >& ips)
+{
+  vector<string> result;
+  result.reserve(ips.size());
+
+  for(const auto& ip : ips) {
+      result.emplace_back(ip.second);
+  }
+  if(result.empty()) {
+    throw std::invalid_argument("The IP list cannot be empty");
+  }
+  return result;
+}
+
+static vector<string> lua_dblookup(const string& record, uint16_t qtype)
+{
+  DNSName rec;
+  vector<string> ret;
+  try {
+    rec = DNSName(record);
+  }
+  catch (const std::exception& e) {
+    g_log << Logger::Error << "DB lookup cannot be performed, the name (" << record << ") is malformed: " << e.what() << endl;
+    return ret;
+  }
+  try {
+    SOAData soaData;
+
+    if (!getAuth(rec, qtype, &soaData)) {
+      return ret;
+    }
+
+    vector<DNSZoneRecord> drs = lookup(rec, qtype, soaData.domain_id);
+    for (const auto& drec : drs) {
+      ret.push_back(drec.dr.getContent()->getZoneRepresentation());
+    }
+  }
+  catch (std::exception& e) {
+    g_log << Logger::Error << "Failed to do DB lookup for " << rec << "/" << qtype << ": " << e.what() << endl;
+  }
+  return ret;
+}
+
+static void lua_include(LuaContext& lua, string record)
+{
+  DNSName rec;
+  try {
+    rec = DNSName(record) + s_lua_record_ctx->zone;
+  } catch (const std::exception &e){
+    g_log<<Logger::Error<<"Included record cannot be loaded, the name ("<<record<<") is malformed: "<<e.what()<<endl;
+    return;
+  }
+  try {
+    vector<DNSZoneRecord> drs = lookup(rec, QType::LUA, s_lua_record_ctx->zone_record.domain_id);
+    for(const auto& dr : drs) {
+      auto lr = getRR<LUARecordContent>(dr.dr);
+      lua.executeCode(lr->getCode());
+    }
+  }
+  catch(std::exception& e) {
+    g_log<<Logger::Error<<"Failed to load include record for Lua record "<<rec<<": "<<e.what()<<endl;
+  }
+}
+
+// Lua variables available to the user
+
+static std::unordered_map<std::string, int> lua_variables{
+  {"ASn", GeoIPInterface::GeoIPQueryAttribute::ASn},
+  {"City", GeoIPInterface::GeoIPQueryAttribute::City},
+  {"Continent", GeoIPInterface::GeoIPQueryAttribute::Continent},
+  {"Country", GeoIPInterface::GeoIPQueryAttribute::Country},
+  {"Country2", GeoIPInterface::GeoIPQueryAttribute::Country2},
+  {"Name", GeoIPInterface::GeoIPQueryAttribute::Name},
+  {"Region", GeoIPInterface::GeoIPQueryAttribute::Region},
+  {"Location", GeoIPInterface::GeoIPQueryAttribute::Location}
+};
+
+static void setupLuaRecords(LuaContext& lua)
+{
+  lua.writeFunction("latlon", []() {
+      return lua_latlon();
+    });
+  lua.writeFunction("latlonloc", []() {
+      return lua_latlonloc();
+    });
+  lua.writeFunction("closestMagic", []() {
+      return lua_closestMagic();
+    });
+  lua.writeFunction("latlonMagic", [](){
+      return lua_latlonMagic();
     });
 
-  lua.writeFunction("pickrandomsample", [](int n, const iplist_t& ips) {
-      vector<string> items = convStringList(ips);
-         return pickRandomSample<string>(n, items);
+  lua.writeFunction("createForward", []() {
+      return lua_createForward();
+    });
+  lua.writeFunction("createForward6", []() {
+      return lua_createForward6();
     });
 
-  lua.writeFunction("pickhashed", [](const iplist_t& ips) {
-      vector<string> items = convStringList(ips);
-      return pickHashed<string>(s_lua_record_ctx->bestwho, items);
+  lua.writeFunction("createReverse", [](string format, boost::optional<std::unordered_map<string,string>> e){
+      return lua_createReverse(format, e);
     });
-  /*
-   * Returns a random IP address from the supplied list, as weighted by the
-   * various ``weight`` parameters
-   * @example pickwrandom({ {100, '1.2.3.4'}, {50, '5.4.3.2'}, {1, '192.168.1.0'} })
-   */
-  lua.writeFunction("pickwrandom", [](std::unordered_map<int, wiplist_t> ips) {
-      vector< pair<int, string> > items = convIntStringPairList(ips);
-      return pickWeightedRandom<string>(items);
+  lua.writeFunction("createReverse6", [](const string &format, boost::optional<std::unordered_map<string,string>> excp){
+      return lua_createReverse6(format, excp);
     });
 
-  /*
-   * Based on the hash of `bestwho`, returns an IP address from the list
-   * supplied, as weighted by the various `weight` parameters
-   * @example pickwhashed({ {15, '1.2.3.4'}, {50, '5.4.3.2'} })
-   */
-  lua.writeFunction("pickwhashed", [](std::unordered_map<int, wiplist_t > ips) {
-      vector< pair<int, string> > items;
+  lua.writeFunction("filterForward", [](const string& address, NetmaskGroup& nmg, boost::optional<string> fallback) -> vector<string> {
+      return lua_filterForward(address, nmg, fallback);
+    });
 
-      items.reserve(ips.size());
-      for (auto& entry : ips) {
-        items.emplace_back(atoi(entry.second[1].c_str()), entry.second[2]);
-      }
+  lua.writeFunction("ifportup", [](int port, const boost::variant<iplist_t, ipunitlist_t>& ips, const boost::optional<std::unordered_map<string,string>> options) {
+      return lua_ifportup(port, ips, options);
+    });
 
-      return pickWeightedHashed<string>(s_lua_record_ctx->bestwho, items);
+  lua.writeFunction("ifurlextup", [](const vector<pair<int, opts_t> >& ipurls, boost::optional<opts_t> options) {
+      return lua_ifurlextup(ipurls, options);
     });
 
-  /*
-   * Based on the hash of the record name, return an IP address from the list
-   * supplied, as weighted by the various `weight` parameters
-   * @example picknamehashed({ {15, '1.2.3.4'}, {50, '5.4.3.2'} })
-   */
-  lua.writeFunction("picknamehashed", [](std::unordered_map<int, wiplist_t > ips) {
-      vector< pair<int, string> > items;
+  lua.writeFunction("ifurlup", [](const std::string& url, const boost::variant<iplist_t, ipunitlist_t>& ips, boost::optional<opts_t> options) {
+      return lua_ifurlup(url, ips, options);
+    });
 
-      items.reserve(ips.size());
-      for(auto& i : ips)
-      {
-        items.emplace_back(atoi(i.second[1].c_str()), i.second[2]);
-      }
+  lua.writeFunction("pickrandom", [](const iplist_t& ips) {
+      return lua_pickrandom(ips);
+    });
 
-      return pickWeightedNameHashed<string>(s_lua_record_ctx->qname, items);
+  lua.writeFunction("pickselfweighted", [](const std::string& url, const iplist_t& ips, boost::optional<opts_t> options) {
+      return lua_pickselfweighted(url, ips, options);
     });
-  /*
-   * Based on the hash of `bestwho`, returns an IP address from the list
-   * supplied, as weighted by the various `weight` parameters and distributed consistently
-   * @example pickchashed({ {15, '1.2.3.4'}, {50, '5.4.3.2'} })
-   */
-  lua.writeFunction("pickchashed", [](const std::unordered_map<int, wiplist_t>& ips) {
-    std::vector<std::pair<int, std::string>> items;
 
-    items.reserve(ips.size());
-    for (const auto& entry : ips) {
-      items.emplace_back(atoi(entry.second.at(1).c_str()), entry.second.at(2));
-    }
+  lua.writeFunction("pickrandomsample", [](int n, const iplist_t& ips) {
+      return lua_pickrandomsample(n, ips);
+    });
 
-    return pickConsistentWeightedHashed(s_lua_record_ctx->bestwho, items);
-  });
+  lua.writeFunction("pickhashed", [](const iplist_t& ips) {
+      return lua_pickhashed(ips);
+    });
+  lua.writeFunction("pickwrandom", [](std::unordered_map<int, wiplist_t> ips) {
+      return lua_pickwrandom(ips);
+    });
 
-  lua.writeFunction("pickclosest", [](const iplist_t& ips) {
-      vector<ComboAddress> conv = convComboAddressList(ips);
+  lua.writeFunction("pickwhashed", [](std::unordered_map<int, wiplist_t > ips) {
+      return lua_pickwhashed(ips);
+    });
 
-      return pickclosest(s_lua_record_ctx->bestwho, conv).toString();
+  lua.writeFunction("picknamehashed", [](std::unordered_map<int, wiplist_t > ips) {
+      return lua_picknamehashed(ips);
+    });
+  lua.writeFunction("pickchashed", [](const std::unordered_map<int, wiplist_t>& ips) {
+      return lua_pickchashed(ips);
+    });
 
+  lua.writeFunction("pickclosest", [](const iplist_t& ips) {
+      return lua_pickclosest(ips);
     });
 
   if (g_luaRecordExecLimit > 0) {
       lua.executeCode(boost::str(boost::format("debug.sethook(report, '', %d)") % g_luaRecordExecLimit));
   }
 
-  lua.writeFunction("report", [](string /* event */, boost::optional<string> /* line */){
-      throw std::runtime_error("Script took too long");
+  lua.writeFunction("report", [](string event, boost::optional<string> line){
+      return lua_report(event, line);
     });
 
   lua.writeFunction("geoiplookup", [](const string &ip, const GeoIPInterface::GeoIPQueryAttribute attr) {
-    return getGeo(ip, attr);
-  });
-  lua.writeVariable("GeoIPQueryAttribute", std::unordered_map<std::string, int>{{"ASn", GeoIPInterface::GeoIPQueryAttribute::ASn}, {"City", GeoIPInterface::GeoIPQueryAttribute::City}, {"Continent", GeoIPInterface::GeoIPQueryAttribute::Continent}, {"Country", GeoIPInterface::GeoIPQueryAttribute::Country}, {"Country2", GeoIPInterface::GeoIPQueryAttribute::Country2}, {"Name", GeoIPInterface::GeoIPQueryAttribute::Name}, {"Region", GeoIPInterface::GeoIPQueryAttribute::Region}, {"Location", GeoIPInterface::GeoIPQueryAttribute::Location}});
+      return lua_geoiplookup(ip, attr);
+    });
 
-  typedef const boost::variant<string,vector<pair<int,string> > > combovar_t;
+  lua.writeVariable("GeoIPQueryAttribute", lua_variables);
 
   lua.writeFunction("asnum", [](const combovar_t& asns) {
-      string res=getGeo(s_lua_record_ctx->bestwho.toString(), GeoIPInterface::ASn);
-      return doCompare(asns, res, [](const std::string& a, const std::string& b) {
-          return !strcasecmp(a.c_str(), b.c_str());
-        });
+      return lua_asnum(asns);
     });
   lua.writeFunction("continent", [](const combovar_t& continent) {
-     string res=getGeo(s_lua_record_ctx->bestwho.toString(), GeoIPInterface::Continent);
-      return doCompare(continent, res, [](const std::string& a, const std::string& b) {
-          return !strcasecmp(a.c_str(), b.c_str());
-        });
+      return lua_continent(continent);
     });
   lua.writeFunction("continentCode", []() {
-      string unknown("unknown");
-      string res = getGeo(s_lua_record_ctx->bestwho.toString(), GeoIPInterface::Continent);
-      if ( res == unknown ) {
-       return std::string("--");
-      }
-      return res;
+      return lua_continentCode();
     });
   lua.writeFunction("country", [](const combovar_t& var) {
-      string res = getGeo(s_lua_record_ctx->bestwho.toString(), GeoIPInterface::Country2);
-      return doCompare(var, res, [](const std::string& a, const std::string& b) {
-          return !strcasecmp(a.c_str(), b.c_str());
-        });
-
+      return lua_country(var);
     });
   lua.writeFunction("countryCode", []() {
-      string unknown("unknown");
-      string res = getGeo(s_lua_record_ctx->bestwho.toString(), GeoIPInterface::Country2);
-      if ( res == unknown ) {
-       return std::string("--");
-      }
-      return res;
+      return lua_countryCode();
     });
   lua.writeFunction("region", [](const combovar_t& var) {
-      string res = getGeo(s_lua_record_ctx->bestwho.toString(), GeoIPInterface::Region);
-      return doCompare(var, res, [](const std::string& a, const std::string& b) {
-          return !strcasecmp(a.c_str(), b.c_str());
-        });
-
+      return lua_region(var);
     });
   lua.writeFunction("regionCode", []() {
-      string unknown("unknown");
-      string res = getGeo(s_lua_record_ctx->bestwho.toString(), GeoIPInterface::Region);
-      if ( res == unknown ) {
-       return std::string("--");
-      }
-      return res;
+      return lua_regionCode();
     });
   lua.writeFunction("netmask", [](const iplist_t& ips) {
-      for(const auto& i :ips) {
-        Netmask nm(i.second);
-        if(nm.match(s_lua_record_ctx->bestwho))
-          return true;
-      }
-      return false;
+      return lua_netmask(ips);
     });
-  /* {
-       {
-        {'192.168.0.0/16', '10.0.0.0/8'},
-        {'192.168.20.20', '192.168.20.21'}
-       },
-       {
-        {'0.0.0.0/0'}, {'192.0.2.1'}
-       }
-     }
-  */
   lua.writeFunction("view", [](const vector<pair<int, vector<pair<int, iplist_t> > > >& in) {
-      for(const auto& rule : in) {
-        const auto& netmasks=rule.second[0].second;
-        const auto& destinations=rule.second[1].second;
-        for(const auto& nmpair : netmasks) {
-          Netmask nm(nmpair.second);
-          if(nm.match(s_lua_record_ctx->bestwho)) {
-            if (destinations.empty()) {
-              throw std::invalid_argument("The IP list cannot be empty (for netmask " + nm.toString() + ")");
-            }
-            return destinations[dns_random(destinations.size())].second;
-          }
-        }
-      }
-      return std::string();
+      return lua_view(in);
     });
 
   lua.writeFunction("all", [](const vector< pair<int,string> >& ips) {
-      vector<string> result;
-         result.reserve(ips.size());
-
-      for(const auto& ip : ips) {
-          result.emplace_back(ip.second);
-      }
-      if(result.empty()) {
-        throw std::invalid_argument("The IP list cannot be empty");
-      }
-      return result;
+      return lua_all(ips);
     });
 
   lua.writeFunction("dblookup", [](const string& record, uint16_t qtype) {
-    DNSName rec;
-    vector<string> ret;
-    try {
-      rec = DNSName(record);
-    }
-    catch (const std::exception& e) {
-      g_log << Logger::Error << "DB lookup cannot be performed, the name (" << record << ") is malformed: " << e.what() << endl;
-      return ret;
-    }
-    try {
-      SOAData soaData;
-
-      if (!getAuth(rec, qtype, &soaData)) {
-        return ret;
-      }
-
-      vector<DNSZoneRecord> drs = lookup(rec, qtype, soaData.domain_id);
-      for (const auto& drec : drs) {
-        ret.push_back(drec.dr.getContent()->getZoneRepresentation());
-      }
-    }
-    catch (std::exception& e) {
-      g_log << Logger::Error << "Failed to do DB lookup for " << rec << "/" << qtype << ": " << e.what() << endl;
-    }
-    return ret;
-  });
+      return lua_dblookup(record, qtype);
+    });
 
   lua.writeFunction("include", [&lua](string record) {
-      DNSName rec;
-      try {
-        rec = DNSName(record) + s_lua_record_ctx->zone;
-      } catch (const std::exception &e){
-        g_log<<Logger::Error<<"Included record cannot be loaded, the name ("<<record<<") is malformed: "<<e.what()<<endl;
-        return;
-      }
-      try {
-        vector<DNSZoneRecord> drs = lookup(rec, QType::LUA, s_lua_record_ctx->zone_record.domain_id);
-        for(const auto& dr : drs) {
-          auto lr = getRR<LUARecordContent>(dr.dr);
-          lua.executeCode(lr->getCode());
-        }
-      }
-      catch(std::exception& e) {
-        g_log<<Logger::Error<<"Failed to load include record for Lua record "<<rec<<": "<<e.what()<<endl;
-      }
+      lua_include(lua, record);
     });
 }