htmlescape
htmlhelp
httpapi
+httpcode
httpdomain
hubert
iana
- ``stringmatch``: check ``url`` for this string, only declare 'up' if found
- ``useragent``: Set the HTTP "User-Agent" header in the requests. By default it is set to "PowerDNS Authoritative Server"
- ``byteslimit``: Limit the maximum download size to ``byteslimit`` bytes (default 0 meaning no limit).
+ - ``httpcode``: Set the HTTP status code to match in response. (default is 200)
An example of a list of address sets:
if (cd.opts.count("byteslimit")) {
byteslimit = static_cast<size_t>(std::atoi(cd.opts.at("byteslimit").c_str()));
}
- MiniCurl mc(useragent);
+ int http_code = 200;
+ if (cd.opts.count("httpcode") != 0) {
+ http_code = pdns::checked_stoi<int>(cd.opts.at("httpcode"));
+ }
+
+ MiniCurl minicurl(useragent, false);
string content;
const ComboAddress* rem = nullptr;
if (cd.opts.count("source")) {
ComboAddress src(cd.opts.at("source"));
- content=mc.getURL(cd.url, rem, &src, timeout, false, false, byteslimit);
+ content=minicurl.getURL(cd.url, rem, &src, timeout, false, false, byteslimit, http_code);
}
else {
- content=mc.getURL(cd.url, rem, nullptr, timeout, false, false, byteslimit);
+ content=minicurl.getURL(cd.url, rem, nullptr, timeout, false, false, byteslimit, http_code);
}
if (cd.opts.count("stringmatch") && content.find(cd.opts.at("stringmatch")) == string::npos) {
throw std::runtime_error(boost::str(boost::format("unable to match content with `%s`") % cd.opts.at("stringmatch")));
}
}
-MiniCurl::MiniCurl(const string& useragent)
+MiniCurl::MiniCurl(const string& useragent, bool failonerror) : d_failonerror(failonerror)
{
#ifdef CURL_STRICTER
d_curl = std::unique_ptr<CURL, decltype(&curl_easy_cleanup)>(curl_easy_init(), curl_easy_cleanup);
curl_easy_setopt(getCURLPtr(d_curl), CURLOPT_SSL_VERIFYPEER, verify);
curl_easy_setopt(getCURLPtr(d_curl), CURLOPT_SSL_VERIFYHOST, verify ? 2 : 0);
- curl_easy_setopt(getCURLPtr(d_curl), CURLOPT_FAILONERROR, true);
+ curl_easy_setopt(getCURLPtr(d_curl), CURLOPT_FAILONERROR, d_failonerror);
curl_easy_setopt(getCURLPtr(d_curl), CURLOPT_URL, str.c_str());
curl_easy_setopt(getCURLPtr(d_curl), CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(getCURLPtr(d_curl), CURLOPT_WRITEDATA, this);
d_data.clear();
}
-std::string MiniCurl::getURL(const std::string& str, const ComboAddress* rem, const ComboAddress* src, int timeout, [[maybe_unused]] bool fastopen, bool verify, size_t byteslimit)
+std::string MiniCurl::getURL(const std::string& str, const ComboAddress* rem, const ComboAddress* src, int timeout, [[maybe_unused]] bool fastopen, bool verify, size_t byteslimit, int http_status)
{
setupURL(str, rem, src, timeout, byteslimit, fastopen, verify);
auto res = curl_easy_perform(getCURLPtr(d_curl));
long http_code = 0;
curl_easy_getinfo(getCURLPtr(d_curl), CURLINFO_RESPONSE_CODE, &http_code);
- if ((res != CURLE_OK && res != CURLE_ABORTED_BY_CALLBACK) || http_code != 200) {
+ if ((res != CURLE_OK && res != CURLE_ABORTED_BY_CALLBACK) || http_code != http_status) {
throw std::runtime_error("Unable to retrieve URL ("+std::to_string(http_code)+"): "+string(curl_easy_strerror(res)));
}
std::string ret = d_data;
static void init();
- MiniCurl(const string& useragent="MiniCurl/0.0");
+ MiniCurl(const string& useragent="MiniCurl/0.0", bool failonerror=true);
~MiniCurl();
MiniCurl& operator=(const MiniCurl&) = delete;
- std::string getURL(const std::string& str, const ComboAddress* rem=nullptr, const ComboAddress* src=nullptr, int timeout = 2, bool fastopen = false, bool verify = false, size_t byteslimit = 0);
+ std::string getURL(const std::string& str, const ComboAddress* rem=nullptr, const ComboAddress* src=nullptr, int timeout = 2, bool fastopen = false, bool verify = false, size_t byteslimit = 0, int http_status = 200);
std::string postURL(const std::string& str, const std::string& postdata, MiniCurlHeaders& headers, int timeout = 2, bool fastopen = false, bool verify = false);
private:
std::string d_data;
size_t d_byteslimit{};
bool d_fresh{true};
+ bool d_failonerror;
void setupURL(const std::string& str, const ComboAddress* rem, const ComboAddress* src, int timeout, size_t byteslimit, bool fastopen, bool verify);
void setHeaders(const MiniCurlHeaders& headers);
"{{ '192.168.42.101', '{prefix}.101' }}, "
"{{ stringmatch='pong' }}) ")
+usa-404 IN LUA A ( ";include('config') "
+ "return ifurlup('http://www.lua.org:8080/404', "
+ "USAips, {{ httpcode='404' }}) ")
+
ifurlextup IN LUA A "ifurlextup({{{{['192.168.0.1']='http://{prefix}.101:8080/404',['192.168.0.2']='http://{prefix}.102:8080/404'}}, {{['192.168.0.3']='http://{prefix}.101:8080/'}}}})"
nl IN LUA A ( ";include('config') "
self.assertRcodeEqual(res, dns.rcode.NOERROR)
self.assertAnyRRsetInAnswer(res, reachable_rrs)
+ def testIfurlupHTTPCode(self):
+ """
+ Basic ifurlup() test, with non-default HTTP code
+ """
+ reachable = [
+ '{prefix}.103'.format(prefix=self._PREFIX)
+ ]
+ unreachable = ['192.168.42.105']
+ ips = reachable + unreachable
+ all_rrs = []
+ reachable_rrs = []
+ for ip in ips:
+ rr = dns.rrset.from_text('usa-404.example.org.', 0, dns.rdataclass.IN, 'A', ip)
+ all_rrs.append(rr)
+ if ip in reachable:
+ reachable_rrs.append(rr)
+
+ query = dns.message.make_query('usa-404.example.org', 'A')
+ res = self.sendUDPQuery(query)
+ self.assertRcodeEqual(res, dns.rcode.NOERROR)
+ self.assertAnyRRsetInAnswer(res, all_rrs)
+
+ # the timeout in the LUA health checker is 2 second, so we make sure to wait slightly longer here
+ time.sleep(3)
+ res = self.sendUDPQuery(query)
+ self.assertRcodeEqual(res, dns.rcode.NOERROR)
+ self.assertAnyRRsetInAnswer(res, reachable_rrs)
+
def testIfurlupMultiSet(self):
"""
Basic ifurlup() test with mutiple sets