:Secondary operation: ``getUnfreshSlaveInfos``, ``startTransaction``, ``commitTransaction``, ``abortTransaction``, ``feedRecord``, ``setFresh``
:DNSSEC operation (live-signing): ``getDomainKeys``, ``getBeforeAndAfterNamesAbsolute``
:Filling the Zone Cache: ``getAllDomains``
+:HTTP API specific: ``APILookup``
``initialize``
~~~~~~~~~~~~~~
Called to initialize the backend. This is not called for HTTP connector.
You should do your initializations here.
-- Mandatory: Yes (except HTTP connector)
+- Mandatory: yes (except HTTP connector)
- Parameters: all parameters in connection string
- Reply: true on success / false on failure
This method is used to do the basic query. You can omit auth, but if you
are using DNSSEC this can lead into trouble.
-- Mandatory: Yes
+- Mandatory: yes
- Parameters: qtype, qname, zone_id
- Optional parameters: remote, local, real-remote
- Reply: array of ``qtype,qname,content,ttl,domain_id,scopeMask,auth``
{"result":[{"qtype":"A", "qname":"www.example.com", "content":"203.0.113.2", "ttl": 60}]}
+``APILookup``
+~~~~~~~~~~~~~
+
+This method is similar to :ref:`remote-lookup`, but also returns disabled
+records. It allows for an extra optional parameter, ``include_disabled`` which,
+if present and set to false, will only return non-disabled records (in which
+case, the behaviour is equivalent to the ``lookup`` method.)
+
+- Mandatory: no (required if the HTTP API is to be used)
+- Parameters: qtype, qname, zone_id
+- Optional parameters: remote, local, real-remote, include_disabled
+- Reply: array of ``qtype,qname,content,ttl,domain_id,scopeMask,auth,disabled``
+- Optional values: scopeMask and auth
+
``list``
~~~~~~~~
should take care of setting auth to appropriate value, otherwise things
can go wrong.
-- Mandatory: No (Gives AXFR support)
+- Mandatory: no (gives AXFR support)
- Parameters: zonename, domain_id
- Optional parameters: domain_id
- Reply: array of ``qtype,qname,content,ttl,domain_id,scopeMask,auth``
always return something, if there are no values, you shall return an empty
array.
-- Mandatory: No
+- Mandatory: no
- Parameters: name, kind
- Reply: array of strings
array value. The old value is discarded. Value can be an empty array,
which can be interpreted as deletion request.
-- Mandatory: No
+- Mandatory: no
- Parameters: name, kind, value
- Reply: true on success, false on failure
Adds key into local storage. See :ref:`remote-getdomainkeys` for more information.
-- Mandatory: No
+- Mandatory: no
- Parameters: name, key=\ ``<flags,active,published,content>``, id
- Reply: true for success, false for failure
Removes key id from domain name.
-- Mandatory: No
+- Mandatory: no
- Parameters: name, id
- Reply: true for success, false for failure
Activates key id for domain name.
-- Mandatory: No
+- Mandatory: no
- Parameters: name, id
- Reply: true for success, false for failure
Deactivates key id for domain name.
-- Mandatory: No
+- Mandatory: no
- Parameters: name, id
- Reply: true for success, false for failure
Publish key id for domain name.
-- Mandatory: No
+- Mandatory: no
- Parameters: name, id
- Reply: true for success, false for failure
Unpublish key id for domain name.
-- Mandatory: No
+- Mandatory: no
- Parameters: name, id
- Reply: true for success, false for failure
Retrieves the key needed to sign AXFR.
-- Mandatory: No
+- Mandatory: no
- Parameters: name
- Reply: algorithm, content
kind:NATIVE, id:-1, notified_serial:-1, last_check:0, masters: [].
Masters, if present, must be array of strings.
-- Mandatory: No
+- Mandatory: no
- Parameters: name
- Reply: zone
- Optional values: serial, kind, id, notified_serial, last_check,
Updates last notified serial for the domain id. Any errors are ignored.
-- Mandatory: No
+- Mandatory: no
- Parameters: id, serial
- Reply: true for success, false for failure
Determines whether given IP is primary for given domain name.
-- Mandatory: No
+- Mandatory: no
- Parameters: name,ip
- Reply: true for success, false for failure.
the address where notify is received from. nsset is array of NS resource
records.
-- Mandatory: No
+- Mandatory: no
- Parameters: ip,domain,nsset,account
- Reply: true for success, false for failure. can also return
account=>name of account< and nameserver.
Creates new domain. This method is called when NOTIFY is received and
you are superslaving.
- - Mandatory: No
+ - Mandatory: no
- Parameters: ip, domain
- Optional parameters: nameserver, account
- Reply: true for success, false for failure
This method replaces a given resource record with new set. The new qtype
can be different from the old.
-- Mandatory: No
+- Mandatory: no
- Parameters: domain_id, qname, qtype, rrset
- Reply: true for success, false for failure
Asks to feed new record into system. If startTransaction was called,
trxId identifies a transaction. It is not always called by PowerDNS.
-- Mandatory: No
+- Mandatory: no
- Parameters: rr, trxid
- Reply: true for success, false for failure
that there exists a non-terminal in between, and this instructs you to
add one. If startTransaction is called, trxid identifies a transaction.
-- Mandatory: No
+- Mandatory: no
- Parameters: nonterm, trxid
- Reply: true for success, false for failure
Same as :ref:`remote-feedents`, but provides NSEC3 hashing
parameters. Note that salt is BYTE value, and can be non-readable text.
-- Mandatory: No
+- Mandatory: no
- Parameters: trxid, domain_id, domain, times, salt, narrow, nonterm
- Reply: true for success, false for failure
Starts a new transaction. Transaction ID is chosen for you. Used to
identify f.ex. AXFR transfer.
-- Mandatory: No
+- Mandatory: no
- Parameters: domain_id, domain, trxid
- Reply: true for success, false for failure
Signals successful transfer and asks to commit data into permanent
storage.
-- Mandatory: No
+- Mandatory: no
- Parameters: trxid
- Reply: true for success, false for failure
Signals failed transaction, and that you should rollback any changes.
-- Mandatory: No
+- Mandatory: no
- Parameters: trxid
- Reply: true for success, false for failure
Asks you to calculate a new serial based on the given data and update
the serial.
-- Mandatory: No
+- Mandatory: no
- Parameters: domain,sd
- Reply: true for success, false for failure
Called when a primary freshness check succeeded. This does not indicate the
zone was updated on the primary.
-- Mandatory: No
+- Mandatory: no
- Parameters: id
- Reply: true for success, false for failure
declare(suffix, "any-query", "Any query", record_query + " disabled=0 and name=?");
declare(suffix, "any-id-query", "Any with ID query", record_query + " disabled=0 and name=? and domain_id=?");
+ declare(suffix, "api-id-query", "API basic with ID query", record_query + " (disabled=0 or ?) and type=? and name=? and domain_id=?");
+ declare(suffix, "api-any-id-query", "API any with ID query", record_query + " (disabled=0 or ?) and name=? and domain_id=?");
+
declare(suffix, "list-query", "AXFR query", "SELECT content,ttl,prio,type,domain_id,disabled,name,auth,ordername FROM records WHERE (disabled=0 OR ?) and domain_id=? order by name, type");
declare(suffix, "list-subzone-query", "Subzone listing", record_query + " disabled=0 and (name=? OR name like ?) and domain_id=?");
declare(suffix, "any-query", "Any query", record_query + " disabled=0 and name=?");
declare(suffix, "any-id-query", "Any with ID query", record_query + " disabled=0 and name=? and domain_id=?");
+ declare(suffix, "api-id-query", "API basic with ID query", record_query + " (disabled=0 or disabled=?) and type=? and name=? and domain_id=?");
+ declare(suffix, "api-any-id-query", "API any with ID query", record_query + " (disabled=0 or disabled=?) and name=? and domain_id=?");
+
declare(suffix, "list-query", "AXFR query", "SELECT content,ttl,prio,type,domain_id,disabled,name,auth,CONVERT(varchar(255), ordername, 0) FROM records WHERE (disabled=0 OR disabled=?) and domain_id=? order by name, type");
declare(suffix, "list-subzone-query", "Subzone listing", record_query + " disabled=0 and (name=? OR name like ?) and domain_id=?");
declare(suffix, "any-query", "Any query", record_query + " disabled=false and name=$1");
declare(suffix, "any-id-query", "Any with ID query", record_query + " disabled=false and name=$1 and domain_id=$2");
+ declare(suffix, "api-id-query", "API basic with ID query", record_query + " (disabled=false or $1) and type=$2 and name=$3 and domain_id=$4");
+ declare(suffix, "api-any-id-query", "API any with ID query", record_query + " (disabled=false or $1) and name=$2 and domain_id=$3");
+
declare(suffix, "list-query", "AXFR query", "SELECT content,ttl,prio,type,domain_id,disabled::int,name,auth::int,ordername FROM records WHERE (disabled=false OR $1) and domain_id=$2 order by name, type");
declare(suffix, "list-subzone-query", "Subzone listing", record_query + " disabled=false and (name=$1 OR name like $2) and domain_id=$3");
declare(suffix, "any-query", "Any query", record_query + " disabled=0 and name=:qname");
declare(suffix, "any-id-query", "Any with ID query", record_query + " disabled=0 and name=:qname and domain_id=:domain_id");
+ declare(suffix, "api-id-query", "API basic with ID query", record_query + " (disabled=0 or :include_disabled) and type=:qtype and name=:qname and domain_id=:domain_id");
+ declare(suffix, "api-any-id-query", "API any with ID query", record_query + " (disabled=0 or :include_disabled) and name=:qname and domain_id=:domain_id");
+
declare(suffix, "list-query", "AXFR query", "SELECT content,ttl,prio,type,domain_id,disabled,name,auth,ordername FROM records WHERE (disabled=0 OR :include_disabled) and domain_id=:domain_id order by name, type");
declare(suffix, "list-subzone-query", "Subzone listing", record_query + " disabled=0 and (name=:zone OR name like :wildzone) and domain_id=:domain_id");
return true;
}
-void LMDBBackend::lookup(const QType& type, const DNSName& qdomain, int zoneId, DNSPacket* /* p */)
+void LMDBBackend::lookupInternal(const QType& type, const DNSName& qdomain, int zoneId, DNSPacket* /* p */, bool include_disabled)
{
if (d_dolog) {
g_log << Logger::Warning << "Got lookup for " << qdomain << "|" << type.toString() << " in zone " << zoneId << endl;
d_dtime.set();
}
- d_includedisabled = false;
+ d_includedisabled = include_disabled;
DNSName hunt(qdomain);
DomainInfo di;
bool replaceComments(uint32_t domain_id, const DNSName& qname, const QType& qt, const vector<Comment>& comments) override;
void getAllDomains(vector<DomainInfo>* domains, bool doSerial, bool include_disabled) override;
- void lookup(const QType& type, const DNSName& qdomain, int zoneId, DNSPacket* p = nullptr) override;
+ void lookup(const QType& type, const DNSName& qdomain, int zoneId, DNSPacket* p = nullptr) override { lookupInternal(type, qdomain, zoneId, p, false); }
+ void APILookup(const QType& type, const DNSName& qdomain, int zoneId, DNSPacket* p = nullptr, bool include_disabled = false) override { lookupInternal(type, qdomain, zoneId, p, include_disabled); }
bool get(DNSResourceRecord& rr) override;
bool get(DNSZoneRecord& dzr) override;
void getAllDomainsFiltered(vector<DomainInfo>* domains, const std::function<bool(DomainInfo&)>& allow);
+ void lookupInternal(const QType& type, const DNSName& qdomain, int zoneId, DNSPacket* p, bool include_disabled);
bool getSerial(DomainInfo& di);
bool upgradeToSchemav3();
d_index = 0;
}
+// Similar to lookup above, but passes an extra include_disabled parameter.
+void RemoteBackend::APILookup(const QType& qtype, const DNSName& qdomain, int zoneId, DNSPacket* pkt_p, bool include_disabled)
+{
+ if (d_index != -1) {
+ throw PDNSException("Attempt to lookup while one running");
+ }
+
+ string localIP = "0.0.0.0";
+ string remoteIP = "0.0.0.0";
+ string realRemote = "0.0.0.0/0";
+
+ if (pkt_p != nullptr) {
+ localIP = pkt_p->getLocal().toString();
+ realRemote = pkt_p->getRealRemote().toString();
+ remoteIP = pkt_p->getInnerRemote().toString();
+ }
+
+ Json query = Json::object{
+ {"method", "APILookup"},
+ {"parameters", Json::object{{"qtype", qtype.toString()}, {"qname", qdomain.toString()}, {"remote", remoteIP}, {"local", localIP}, {"real-remote", realRemote}, {"zone-id", zoneId}, {"include-disabled", include_disabled}}}};
+
+ if (!this->send(query) || !this->recv(d_result)) {
+ return;
+ }
+
+ // OK. we have result parameters in result. do not process empty result.
+ if (!d_result["result"].is_array() || d_result["result"].array_items().empty()) {
+ return;
+ }
+
+ d_index = 0;
+}
+
bool RemoteBackend::list(const ZoneName& target, int domain_id, bool include_disabled)
{
if (d_index != -1) {
unsigned int getCapabilities() override;
void lookup(const QType& qtype, const DNSName& qdomain, int zoneId = -1, DNSPacket* pkt_p = nullptr) override;
+ void APILookup(const QType& qtype, const DNSName& qdomain, int zoneId = -1, DNSPacket* pkt_p = nullptr, bool include_disabled = false) override;
bool get(DNSResourceRecord& rr) override;
bool list(const ZoneName& target, int domain_id, bool include_disabled = false) override;
d_ANYNoIdQuery=getArg("any-query");
d_ANYIdQuery=getArg("any-id-query");
+ d_APIIdQuery=getArg("api-id-query");
+ d_APIANYIdQuery=getArg("api-any-id-query");
+
d_listQuery=getArg("list-query");
d_listSubZoneQuery=getArg("list-subzone-query");
d_IdQuery_stmt = nullptr;
d_ANYNoIdQuery_stmt = nullptr;
d_ANYIdQuery_stmt = nullptr;
+ d_APIIdQuery_stmt = nullptr;
+ d_APIANYIdQuery_stmt = nullptr;
d_listQuery_stmt = nullptr;
d_listSubZoneQuery_stmt = nullptr;
d_InfoOfDomainsZoneQuery_stmt = nullptr;
d_qname=qname;
}
+void GSQLBackend::APILookup(const QType& qtype, const DNSName& qname, int domain_id, DNSPacket* /* pkt_p */, bool include_disabled)
+{
+ try {
+ reconnectIfNeeded();
+
+ if(qtype.getCode()!=QType::ANY) {
+ d_query_name = "api-id-query";
+ d_query_stmt = &d_APIIdQuery_stmt;
+ // clang-format off
+ (*d_query_stmt)->
+ bind("include_disabled", (int)include_disabled)->
+ bind("qtype", qtype.toString())->
+ bind("qname", qname)->
+ bind("domain_id", domain_id);
+ // clang-format on
+ } else {
+ // qtype==ANY
+ d_query_name = "api-any-id-query";
+ d_query_stmt = &d_APIANYIdQuery_stmt;
+ // clang-format off
+ (*d_query_stmt)->
+ bind("include_disabled", (int)include_disabled)->
+ bind("qname", qname)->
+ bind("domain_id", domain_id);
+ // clang-format on
+ }
+
+ (*d_query_stmt)->
+ execute();
+ }
+ catch(SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to APILookup '" + qname.toLogString() + "(" + std::to_string(domain_id) + ")|" + qtype.toString() + "':"+e.txtReason());
+ }
+
+ d_list=false;
+ d_qname=qname;
+}
+
bool GSQLBackend::list(const ZoneName &target, int domain_id, bool include_disabled)
{
DLOG(g_log<<"GSQLBackend constructing handle for list of domain id '"<<domain_id<<"'"<<endl);
d_IdQuery_stmt = d_db->prepare(d_IdQuery, 3);
d_ANYNoIdQuery_stmt = d_db->prepare(d_ANYNoIdQuery, 1);
d_ANYIdQuery_stmt = d_db->prepare(d_ANYIdQuery, 2);
+ d_APIIdQuery_stmt = d_db->prepare(d_APIIdQuery, 4);
+ d_APIANYIdQuery_stmt = d_db->prepare(d_APIANYIdQuery, 3);
d_listQuery_stmt = d_db->prepare(d_listQuery, 2);
d_listSubZoneQuery_stmt = d_db->prepare(d_listSubZoneQuery, 3);
d_PrimaryOfDomainsZoneQuery_stmt = d_db->prepare(d_PrimaryOfDomainsZoneQuery, 1);
d_IdQuery_stmt.reset();
d_ANYNoIdQuery_stmt.reset();
d_ANYIdQuery_stmt.reset();
+ d_APIIdQuery_stmt.reset();
+ d_APIANYIdQuery_stmt.reset();
d_listQuery_stmt.reset();
d_listSubZoneQuery_stmt.reset();
d_PrimaryOfDomainsZoneQuery_stmt.reset();
public:
unsigned int getCapabilities() override;
void lookup(const QType &, const DNSName &qdomain, int zoneId, DNSPacket *p=nullptr) override;
+ void APILookup(const QType &qtype, const DNSName &qname, int domain_id, DNSPacket *p=nullptr, bool include_disabled = false) override;
bool list(const ZoneName &target, int domain_id, bool include_disabled=false) override;
bool get(DNSResourceRecord &r) override;
void getAllDomains(vector<DomainInfo>* domains, bool getSerial, bool include_disabled) override;
string d_ANYNoIdQuery;
string d_ANYIdQuery;
+ string d_APIIdQuery;
+ string d_APIANYIdQuery;
+
string d_listQuery;
string d_listSubZoneQuery;
string d_logprefix;
unique_ptr<SSqlStatement> d_IdQuery_stmt;
unique_ptr<SSqlStatement> d_ANYNoIdQuery_stmt;
unique_ptr<SSqlStatement> d_ANYIdQuery_stmt;
+ unique_ptr<SSqlStatement> d_APIIdQuery_stmt;
+ unique_ptr<SSqlStatement> d_APIANYIdQuery_stmt;
unique_ptr<SSqlStatement> d_listQuery_stmt;
unique_ptr<SSqlStatement> d_listSubZoneQuery_stmt;
unique_ptr<SSqlStatement> d_PrimaryOfDomainsZoneQuery_stmt;
return arg().asNum(d_prefix + "-" + key);
}
+// Default API lookup has no support for disabled records and simply wraps lookup()
+void DNSBackend::APILookup(const QType& qtype, const DNSName& qdomain, int zoneId, DNSPacket* pkt_p, bool /* include_disabled */)
+{
+ lookup(qtype, qdomain, zoneId, pkt_p);
+}
+
void BackendFactory::declare(const string& suffix, const string& param, const string& explanation, const string& value)
{
string fullname = d_name + suffix + "-" + param;
//! lookup() initiates a lookup. A lookup without results should not throw!
virtual void lookup(const QType& qtype, const DNSName& qdomain, int zoneId = -1, DNSPacket* pkt_p = nullptr) = 0;
+ virtual void APILookup(const QType& qtype, const DNSName& qdomain, int zoneId = -1, DNSPacket* pkt_p = nullptr, bool include_disabled = false);
virtual bool get(DNSResourceRecord&) = 0; //!< retrieves one DNSResource record, returns false if no more were available
virtual bool get(DNSZoneRecord& zoneRecord);