const void* data;
} pdns_ednsoption_t;
+ typedef enum
+ {
+ answer = 1,
+ authority = 2,
+ additional = 3
+ } pdns_record_place_t;
+
const char* pdns_ffi_param_get_qname(pdns_ffi_param_t* ref) __attribute__ ((visibility ("default")));
void pdns_ffi_param_get_qname_raw(pdns_ffi_param_t* ref, const char** qname, size_t* qnameSize) __attribute__ ((visibility ("default")));
uint16_t pdns_ffi_param_get_qtype(const pdns_ffi_param_t* ref) __attribute__ ((visibility ("default")));
void pdns_ffi_param_set_variable(pdns_ffi_param_t* ref, bool variable) __attribute__ ((visibility ("default")));
void pdns_ffi_param_set_ttl_cap(pdns_ffi_param_t* ref, uint32_t ttl) __attribute__ ((visibility ("default")));
void pdns_ffi_param_set_log_query(pdns_ffi_param_t* ref, bool logQuery) __attribute__ ((visibility ("default")));
+ void pdns_ffi_param_set_rcode(pdns_ffi_param_t* ref, int rcode) __attribute__ ((visibility ("default")));
+ void pdns_ffi_param_set_follow_cname_records(pdns_ffi_param_t* ref, bool follow) __attribute__ ((visibility ("default")));
+ bool pdns_ffi_param_add_record(pdns_ffi_param_t *ref, const char* name, uint16_t type, uint32_t ttl, const char* content, size_t contentSize, pdns_record_place_t place) __attribute__ ((visibility ("default")));
}
RecursorLua4::RecursorLua4() { prepareContext(); }
-static int followCNAMERecords(vector<DNSRecord>& ret, const QType& qtype)
-{
- vector<DNSRecord> resolved;
- DNSName target;
- for(const DNSRecord& rr : ret) {
- if(rr.d_type == QType::CNAME) {
- auto rec = getRR<CNAMERecordContent>(rr);
- if(rec) {
- target=rec->getTarget();
- break;
- }
- }
- }
- if(target.empty())
- return 0;
-
- int rcode=directResolve(target, qtype, 1, resolved); // 1 == class
-
- for(const DNSRecord& rr : resolved) {
- ret.push_back(rr);
- }
- return rcode;
-
-}
-
static int getFakeAAAARecords(const DNSName& qname, const std::string& prefix, vector<DNSRecord>& ret)
{
int rcode=directResolve(qname, QType(QType::A), 1, ret);
struct pdns_ffi_param
{
public:
- pdns_ffi_param(const DNSName& qname_, uint16_t qtype_, const ComboAddress& local_, const ComboAddress& remote_, const Netmask& ednssubnet_, std::vector<std::string>& policyTags_, const EDNSOptionViewMap& ednsOptions_, std::string& requestorId_, std::string& deviceId_, std::string& deviceName_, uint32_t& ttlCap_, bool& variable_, bool tcp_, bool& logQuery_): qname(qname_), local(local_), remote(remote_), ednssubnet(ednssubnet_), policyTags(policyTags_), ednsOptions(ednsOptions_), requestorId(requestorId_), deviceId(deviceId_), deviceName(deviceName_), ttlCap(ttlCap_), variable(variable_), logQuery(logQuery_), qtype(qtype_), tcp(tcp_)
+ pdns_ffi_param(const DNSName& qname_, uint16_t qtype_, const ComboAddress& local_, const ComboAddress& remote_, const Netmask& ednssubnet_, std::vector<std::string>& policyTags_, std::vector<DNSRecord>& records_, const EDNSOptionViewMap& ednsOptions_, std::string& requestorId_, std::string& deviceId_, std::string& deviceName_, boost::optional<int>& rcode_, uint32_t& ttlCap_, bool& variable_, bool tcp_, bool& logQuery_, bool& followCNAMERecords_): qname(qname_), local(local_), remote(remote_), ednssubnet(ednssubnet_), policyTags(policyTags_), records(records_), ednsOptions(ednsOptions_), requestorId(requestorId_), deviceId(deviceId_), deviceName(deviceName_), rcode(rcode_), ttlCap(ttlCap_), variable(variable_), logQuery(logQuery_), followCNAMERecords(followCNAMERecords_), qtype(qtype_), tcp(tcp_)
{
}
const ComboAddress& remote;
const Netmask& ednssubnet;
std::vector<std::string>& policyTags;
+ std::vector<DNSRecord>& records;
const EDNSOptionViewMap& ednsOptions;
std::string& requestorId;
std::string& deviceId;
std::string& deviceName;
+ boost::optional<int>& rcode;
uint32_t& ttlCap;
bool& variable;
bool& logQuery;
+ bool& followCNAMERecords;
unsigned int tag{0};
uint16_t qtype;
bool tcp;
};
-unsigned int RecursorLua4::gettag_ffi(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::vector<std::string>* policyTags, LuaContext::LuaObject& data, const EDNSOptionViewMap& ednsOptions, bool tcp, std::string& requestorId, std::string& deviceId, std::string& deviceName, uint32_t& ttlCap, bool& variable, bool& logQuery) const
+unsigned int RecursorLua4::gettag_ffi(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::vector<std::string>* policyTags, std::vector<DNSRecord>& records, LuaContext::LuaObject& data, const EDNSOptionViewMap& ednsOptions, bool tcp, std::string& requestorId, std::string& deviceId, std::string& deviceName, boost::optional<int>& rcode, uint32_t& ttlCap, bool& variable, bool& logQuery, bool& followCNAMERecords) const
{
if (d_gettag_ffi) {
- pdns_ffi_param_t param(qname, qtype, local, remote, ednssubnet, *policyTags, ednsOptions, requestorId, deviceId, deviceName, ttlCap, variable, tcp, logQuery);
+ pdns_ffi_param_t param(qname, qtype, local, remote, ednssubnet, *policyTags, records, ednsOptions, requestorId, deviceId, deviceName, rcode, ttlCap, variable, tcp, logQuery, followCNAMERecords);
auto ret = d_gettag_ffi(¶m);
if (ret) {
{
ref->logQuery = logQuery;
}
+
+void pdns_ffi_param_set_rcode(pdns_ffi_param_t* ref, int rcode)
+{
+ ref->rcode = rcode;
+}
+
+void pdns_ffi_param_set_follow_cname_records(pdns_ffi_param_t* ref, bool follow)
+{
+ ref->followCNAMERecords = follow;
+}
+
+bool pdns_ffi_param_add_record(pdns_ffi_param_t *ref, const char* name, uint16_t type, uint32_t ttl, const char* content, size_t contentSize, pdns_record_place_t place)
+{
+ try {
+ DNSRecord dr;
+ dr.d_name = DNSName(name);
+ dr.d_ttl = ttl;
+ dr.d_type = type;
+ dr.d_class = QClass::IN;
+ dr.d_place = DNSResourceRecord::Place(place);
+ dr.d_content = DNSRecordContent::mastermake(type, QClass::IN, std::string(content, contentSize));
+ ref->records.push_back(std::move(dr));
+
+ return true;
+ }
+ catch (const std::exception& e) {
+ g_log<<Logger::Error<<"Error attempting to add a record from Lua via pdns_ffi_param_add_record(): "<<e.what()<<endl;
+ return false;
+ }
+}
};
unsigned int gettag(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::vector<std::string>* policyTags, LuaContext::LuaObject& data, const EDNSOptionViewMap&, bool tcp, std::string& requestorId, std::string& deviceId, std::string& deviceName) const;
- unsigned int gettag_ffi(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::vector<std::string>* policyTags, LuaContext::LuaObject& data, const EDNSOptionViewMap&, bool tcp, std::string& requestorId, std::string& deviceId, std::string& deviceName, uint32_t& ttlCap, bool& variable, bool& logQuery) const;
+ unsigned int gettag_ffi(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::vector<std::string>* policyTags, std::vector<DNSRecord>& records, LuaContext::LuaObject& data, const EDNSOptionViewMap& ednsOptions, bool tcp, std::string& requestorId, std::string& deviceId, std::string& deviceName, boost::optional<int>& rcode, uint32_t& ttlCap, bool& variable, bool& logQuery, bool& followCNAMERecords) const;
void maintenance() const;
bool prerpz(DNSQuestion& dq, int& ret) const;
{
}
- DNSComboWriter(const std::string& query, const struct timeval& now, std::vector<std::string>&& policyTags, LuaContext::LuaObject&& data): d_mdp(true, query), d_now(now), d_query(query), d_policyTags(std::move(policyTags)), d_data(std::move(data))
+ DNSComboWriter(const std::string& query, const struct timeval& now, std::vector<std::string>&& policyTags, LuaContext::LuaObject&& data, std::vector<DNSRecord>&& records): d_mdp(true, query), d_now(now), d_query(query), d_policyTags(std::move(policyTags)), d_records(std::move(records)), d_data(std::move(data))
{
}
#endif
std::string d_query;
std::vector<std::string> d_policyTags;
+ std::vector<DNSRecord> d_records;
LuaContext::LuaObject d_data;
EDNSSubnetOpts d_ednssubnet;
shared_ptr<TCPConnection> d_tcpConnection;
+ boost::optional<int> d_rcode{boost::none};
int d_socket;
unsigned int d_tag{0};
uint32_t d_qhash{0};
bool d_variable{false};
bool d_ecsFound{false};
bool d_ecsParsed{false};
+ bool d_followCNAMERecords{false};
bool d_tcp;
};
}
#endif /* NOD_ENABLED */
+int followCNAMERecords(vector<DNSRecord>& ret, const QType& qtype)
+{
+ vector<DNSRecord> resolved;
+ DNSName target;
+ for(const DNSRecord& rr : ret) {
+ if(rr.d_type == QType::CNAME) {
+ auto rec = getRR<CNAMERecordContent>(rr);
+ if(rec) {
+ target=rec->getTarget();
+ break;
+ }
+ }
+ }
+
+ if(target.empty()) {
+ return 0;
+ }
+
+ int rcode = directResolve(target, qtype, QClass::IN, resolved);
+
+ for(DNSRecord& rr : resolved) {
+ ret.push_back(std::move(rr));
+ }
+ return rcode;
+}
+
static void startDoResolve(void *p)
{
auto dc=std::unique_ptr<DNSComboWriter>(reinterpret_cast<DNSComboWriter*>(p));
uint32_t minTTL = dc->d_ttlCap;
SyncRes sr(dc->d_now);
+ sr.setId(MT->getTid());
bool DNSSECOK=false;
if(t_pdl) {
/* preresolve expects res (dq.rcode) to be set to RCode::NoError by default */
int res = RCode::NoError;
+
DNSFilterEngine::Policy appliedPolicy;
std::vector<DNSRecord> spoofed;
RecursorLua4::DNSQuestion dq(dc->d_source, dc->d_destination, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_tcp, variableAnswer, wantsRPZ, logResponse);
tracedQuery=true;
}
-
if(!g_quiet || tracedQuery) {
g_log<<Logger::Warning<<t_id<<" ["<<MT->getTid()<<"/"<<MT->numProcesses()<<"] " << (dc->d_tcp ? "TCP " : "") << "question for '"<<dc->d_mdp.d_qname<<"|"
<<DNSRecordContent::NumberToType(dc->d_mdp.d_qtype)<<"' from "<<dc->getRemote();
g_log<<endl;
}
- sr.setId(MT->getTid());
- if(!dc->d_mdp.d_header.rd)
+ if(!dc->d_mdp.d_header.rd) {
sr.setCacheOnly();
+ }
+
+ if (dc->d_rcode != boost::none) {
+ /* we have a response ready to go, most likely from gettag_ffi */
+ ret = std::move(dc->d_records);
+ res = *dc->d_rcode;
+ if (res == RCode::NoError && dc->d_followCNAMERecords) {
+ res = followCNAMERecords(ret, QType(dc->d_mdp.d_qtype));
+ }
+ goto haveAnswer;
+ }
if (t_pdl) {
t_pdl->prerpz(dq, res);
if(t_pdl) {
try {
if (t_pdl->d_gettag_ffi) {
- dc->d_tag = t_pdl->gettag_ffi(dc->d_source, dc->d_ednssubnet.source, dc->d_destination, qname, qtype, &dc->d_policyTags, dc->d_data, ednsOptions, true, requestorId, deviceId, deviceName, dc->d_ttlCap, dc->d_variable, logQuery);
+ dc->d_tag = t_pdl->gettag_ffi(dc->d_source, dc->d_ednssubnet.source, dc->d_destination, qname, qtype, &dc->d_policyTags, dc->d_records, dc->d_data, ednsOptions, true, requestorId, deviceId, deviceName, dc->d_rcode, dc->d_ttlCap, dc->d_variable, logQuery, dc->d_followCNAMERecords);
}
else if (t_pdl->d_gettag) {
dc->d_tag = t_pdl->gettag(dc->d_source, dc->d_ednssubnet.source, dc->d_destination, qname, qtype, &dc->d_policyTags, dc->d_data, ednsOptions, true, requestorId, deviceId, deviceName);
bool ecsParsed = false;
uint16_t ecsBegin = 0;
uint16_t ecsEnd = 0;
+ std::vector<DNSRecord> records;
+ boost::optional<int> rcode = boost::none;
uint32_t ttlCap = std::numeric_limits<uint32_t>::max();
bool variable = false;
+ bool followCNAMEs = false;
try {
DNSName qname;
uint16_t qtype=0;
if(t_pdl) {
try {
if (t_pdl->d_gettag_ffi) {
- ctag = t_pdl->gettag_ffi(source, ednssubnet.source, destination, qname, qtype, &policyTags, data, ednsOptions, false, requestorId, deviceId, deviceName, ttlCap, variable, logQuery);
+ ctag = t_pdl->gettag_ffi(source, ednssubnet.source, destination, qname, qtype, &policyTags, records, data, ednsOptions, false, requestorId, deviceId, deviceName, rcode, ttlCap, variable, logQuery, followCNAMEs);
}
else if (t_pdl->d_gettag) {
ctag = t_pdl->gettag(source, ednssubnet.source, destination, qname, qtype, &policyTags, data, ednsOptions, false, requestorId, deviceId, deviceName);
return 0;
}
- auto dc = std::unique_ptr<DNSComboWriter>(new DNSComboWriter(question, g_now, std::move(policyTags), std::move(data)));
+ auto dc = std::unique_ptr<DNSComboWriter>(new DNSComboWriter(question, g_now, std::move(policyTags), std::move(data), std::move(records)));
dc->setSocket(fd);
dc->d_tag=ctag;
dc->d_qhash=qhash;
dc->d_ednssubnet = ednssubnet;
dc->d_ttlCap = ttlCap;
dc->d_variable = variable;
+ dc->d_followCNAMERecords = followCNAMEs;
+ dc->d_rcode = rcode;
#ifdef HAVE_PROTOBUF
if (t_protobufServers || t_outgoingProtobufServers) {
dc->d_uuid = std::move(uniqueId);
void distributeAsyncFunction(const std::string& question, const pipefunc_t& func);
int directResolve(const DNSName& qname, const QType& qtype, int qclass, vector<DNSRecord>& ret);
+int followCNAMERecords(std::vector<DNSRecord>& ret, const QType& qtype);
template<class T> T broadcastAccFunction(const boost::function<T*()>& func);