And in the FFI version of gettag.
for(const MOADNSParser::answers_t::value_type& val : mdp.d_answers) {
if(val.first.d_place == DNSResourceRecord::ADDITIONAL && val.first.d_type == QType::OPT) {
eo->d_packetsize=val.first.d_class;
-
+
EDNS0Record stuff;
uint32_t ttl=ntohl(val.first.d_ttl);
static_assert(sizeof(EDNS0Record) == sizeof(uint32_t), "sizeof(EDNS0Record) must match sizeof(uint32_t)");
memcpy(&stuff, &ttl, sizeof(stuff));
-
+
eo->d_extRCode=stuff.extRCode;
eo->d_version=stuff.version;
eo->d_extFlags = ntohs(stuff.extFlags);
}
/* extract all EDNS0 options from a pointer on the beginning rdLen of the OPT RR */
-int getEDNSOptions(const char* optRR, const size_t len, std::map<uint16_t, EDNSOptionView>& options)
+int getEDNSOptions(const char* optRR, const size_t len, EDNSOptionViewMap& options)
{
assert(optRR != NULL);
size_t pos = 0;
if (optionLen > (rdLen - rdPos) || optionLen > (len - pos))
return EINVAL;
- EDNSOptionView view;
- view.content = optRR + pos;
- view.size = optionLen;
- options[optionCode] = view;
+ EDNSOptionViewValue value;
+ value.content = optRR + pos;
+ value.size = optionLen;
+ options[optionCode].values.push_back(std::move(value));
/* skip this option */
pos += optionLen;
/* extract a specific EDNS0 option from a pointer on the beginning rdLen of the OPT RR */
int getEDNSOption(char* optRR, size_t len, uint16_t wantedOption, char ** optionValue, size_t * optionValueSize);
-struct EDNSOptionView
+struct EDNSOptionViewValue
{
const char* content{nullptr};
uint16_t size{0};
};
+struct EDNSOptionView
+{
+ std::vector<EDNSOptionViewValue> values;
+};
+
+typedef std::map<uint16_t, EDNSOptionView> EDNSOptionViewMap;
+
/* extract all EDNS0 options from a pointer on the beginning rdLen of the OPT RR */
-int getEDNSOptions(const char* optRR, size_t len, std::map<uint16_t, EDNSOptionView>& options);
+int getEDNSOptions(const char* optRR, size_t len, EDNSOptionViewMap& options);
void generateEDNSOption(uint16_t optionCode, const std::string& payload, std::string& res);
boost::optional<Netmask> RecursorLua4::DNSQuestion::getEDNSSubnet() const
{
-
if(ednsOptions) {
for(const auto& o : *ednsOptions) {
if(o.first==EDNSOptionCode::ECS) {
d_lw->registerMember("ttl", &DNSRecord::d_ttl);
d_lw->registerMember("place", &DNSRecord::d_place);
- d_lw->registerMember("size", &EDNSOptionView::size);
- d_lw->registerFunction<std::string(EDNSOptionView::*)()>("getContent", [](const EDNSOptionView& option) { return std::string(option.content, option.size); });
+ d_lw->registerMember("size", &EDNSOptionViewValue::size);
+ d_lw->registerFunction<std::string(EDNSOptionViewValue::*)()>("getContent", [](const EDNSOptionViewValue& value) { return std::string(value.content, value.size); });
+ d_lw->registerFunction<size_t(EDNSOptionView::*)()>("count", [](const EDNSOptionView& option) { return option.values.size(); });
+ d_lw->registerFunction<std::vector<std::pair<int, string>>(EDNSOptionView::*)()>("getValues", [] (const EDNSOptionView& option) {
+ std::vector<std::pair<int, string> > values;
+ for (const auto& value : option.values) {
+ values.push_back(std::make_pair(values.size(), std::string(value.content, value.size)));
+ }
+ return values;
+ });
+
+ /* pre 4.2 API compatibility, when we had only one value for a given EDNS option */
+ d_lw->registerMember<uint16_t(EDNSOptionView::*)>("size", [](const EDNSOptionView& option) -> uint16_t {
+ uint16_t result = 0;
+
+ if (!option.values.empty()) {
+ result = option.values.at(0).size;
+ }
+ return result;
+ },
+ [](EDNSOptionView& option, uint16_t newSize) { (void) newSize; });
+ d_lw->registerFunction<std::string(EDNSOptionView::*)()>("getContent", [](const EDNSOptionView& option) {
+ if (option.values.empty()) {
+ return std::string();
+ }
+ return std::string(option.values.at(0).content, option.values.at(0).size); });
d_lw->registerFunction<string(DNSRecord::*)()>("getContent", [](const DNSRecord& dr) { return dr.d_content->getZoneRepresentation(); });
d_lw->registerFunction<boost::optional<ComboAddress>(DNSRecord::*)()>("getCA", [](const DNSRecord& dr) {
return false; // don't block
}
-unsigned int RecursorLua4::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 std::map<uint16_t, EDNSOptionView>& ednsOptions, bool tcp, std::string& requestorId, std::string& deviceId) const
+unsigned int RecursorLua4::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& ednsOptions, bool tcp, std::string& requestorId, std::string& deviceId) const
{
if(d_gettag) {
auto ret = d_gettag(remote, ednssubnet, local, qname, qtype, ednsOptions, tcp);
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 std::map<uint16_t, EDNSOptionView>& ednsOptions_, std::string& requestorId_, std::string& deviceId_, uint32_t& ttlCap_, bool& variable_, bool tcp_): qname(qname_), local(local_), remote(remote_), ednssubnet(ednssubnet_), policyTags(policyTags_), ednsOptions(ednsOptions_), requestorId(requestorId_), deviceId(deviceId_), ttlCap(ttlCap_), variable(variable_), 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_, const EDNSOptionViewMap& ednsOptions_, std::string& requestorId_, std::string& deviceId_, uint32_t& ttlCap_, bool& variable_, bool tcp_): qname(qname_), local(local_), remote(remote_), ednssubnet(ednssubnet_), policyTags(policyTags_), ednsOptions(ednsOptions_), requestorId(requestorId_), deviceId(deviceId_), ttlCap(ttlCap_), variable(variable_), qtype(qtype_), tcp(tcp_)
{
}
const ComboAddress& remote;
const Netmask& ednssubnet;
std::vector<std::string>& policyTags;
- const std::map<uint16_t, EDNSOptionView>& ednsOptions;
+ const EDNSOptionViewMap& ednsOptions;
std::string& requestorId;
std::string& deviceId;
uint32_t& ttlCap;
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 std::map<uint16_t, EDNSOptionView>& ednsOptions, bool tcp, std::string& requestorId, std::string& deviceId, uint32_t& ttlCap, bool& variable) 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, LuaContext::LuaObject& data, const EDNSOptionViewMap& ednsOptions, bool tcp, std::string& requestorId, std::string& deviceId, uint32_t& ttlCap, bool& variable) const
{
if (d_gettag_ffi) {
pdns_ffi_param_t param(qname, qtype, local, remote, ednssubnet, *policyTags, ednsOptions, requestorId, deviceId, ttlCap, variable, tcp);
return ref->ednssubnet.getBits();
}
-static void fill_edns_option(const EDNSOptionView& view, pdns_ednsoption_t& option)
+static void fill_edns_option(const EDNSOptionViewValue& value, pdns_ednsoption_t& option)
{
- option.len = view.size;
+ option.len = value.size;
option.data = nullptr;
- if (view.size > 0) {
- option.data = view.content;
+ if (value.size > 0) {
+ option.data = value.content;
}
}
return 0;
}
- size_t count = ref->ednsOptions.size();
- ref->ednsOptionsVect.resize(count);
+ size_t totalCount = 0;
+ for (const auto& option : ref->ednsOptions) {
+ totalCount += option.second.values.size();
+ }
+
+ ref->ednsOptionsVect.resize(totalCount);
size_t pos = 0;
- for (const auto& entry : ref->ednsOptions) {
- fill_edns_option(entry.second, ref->ednsOptionsVect.at(pos));
- ref->ednsOptionsVect.at(pos).optionCode = entry.first;
- pos++;
+ for (const auto& option : ref->ednsOptions) {
+ for (const auto& entry : option.second.values) {
+ fill_edns_option(entry, ref->ednsOptionsVect.at(pos));
+ ref->ednsOptionsVect.at(pos).optionCode = option.first;
+ pos++;
+ }
}
*out = ref->ednsOptionsVect.data();
- return count;
+ return totalCount;
}
size_t pdns_ffi_param_get_edns_options_by_code(pdns_ffi_param_t* ref, uint16_t optionCode, const pdns_ednsoption_t** out)
{
const auto& it = ref->ednsOptions.find(optionCode);
- if (it == ref->ednsOptions.cend()) {
+ if (it == ref->ednsOptions.cend() || it->second.values.empty()) {
return 0;
}
- /* the current code deals with only one entry per code, but we will fix that */
- ref->ednsOptionsVect.resize(1);
- fill_edns_option(it->second, ref->ednsOptionsVect.at(0));
- ref->ednsOptionsVect.at(0).optionCode = it->first;
+ ref->ednsOptionsVect.resize(it->second.values.size());
+
+ size_t pos = 0;
+ for (const auto& entry : it->second.values) {
+ fill_edns_option(entry, ref->ednsOptionsVect.at(pos));
+ ref->ednsOptionsVect.at(pos).optionCode = optionCode;
+ pos++;
+ }
*out = ref->ednsOptionsVect.data();
- return 1;
+ return pos;
}
void pdns_ffi_param_set_tag(pdns_ffi_param_t* ref, unsigned int tag)
DNSName followupName;
};
- 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 std::map<uint16_t, EDNSOptionView>&, bool tcp, std::string& requestorId, std::string& deviceId) 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 std::map<uint16_t, EDNSOptionView>&, bool tcp, std::string& requestorId, std::string& deviceId, uint32_t& ttlCap, bool& variable) const;
+ 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) 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, uint32_t& ttlCap, bool& variable) const;
void maintenance() const;
bool prerpz(DNSQuestion& dq, int& ret) const;
d_postresolve);
}
- typedef std::function<std::tuple<unsigned int,boost::optional<std::unordered_map<int,string> >,boost::optional<LuaContext::LuaObject>,boost::optional<std::string>,boost::optional<std::string> >(ComboAddress, Netmask, ComboAddress, DNSName, uint16_t, const std::map<uint16_t, EDNSOptionView>&, bool)> gettag_t;
+ typedef std::function<std::tuple<unsigned int,boost::optional<std::unordered_map<int,string> >,boost::optional<LuaContext::LuaObject>,boost::optional<std::string>,boost::optional<std::string> >(ComboAddress, Netmask, ComboAddress, DNSName, uint16_t, const EDNSOptionViewMap&, bool)> gettag_t;
gettag_t d_gettag; // public so you can query if we have this hooked
typedef std::function<boost::optional<LuaContext::LuaObject>(pdns_ffi_param_t*)> gettag_ffi_t;
gettag_ffi_t d_gettag_ffi;
}
static void getQNameAndSubnet(const std::string& question, DNSName* dnsname, uint16_t* qtype, uint16_t* qclass,
- bool& foundECS, EDNSSubnetOpts* ednssubnet, std::map<uint16_t, EDNSOptionView>* options,
+ bool& foundECS, EDNSSubnetOpts* ednssubnet, EDNSOptionViewMap* options,
bool& foundXPF, ComboAddress* xpfSource, ComboAddress* xpfDest)
{
const bool lookForXPF = xpfSource != nullptr && g_xpfRRCode != 0;
int res = getEDNSOptions(reinterpret_cast<const char*>(&question.at(pos -sizeof(drh->d_clen))), questionLen - pos + (sizeof(drh->d_clen)), *options);
if (res == 0) {
const auto& it = options->find(EDNSOptionCode::ECS);
- if (it != options->end() && it->second.content != nullptr && it->second.size > 0) {
+ if (it != options->end() && !it->second.values.empty() && it->second.values.at(0).content != nullptr && it->second.values.at(0).size > 0) {
EDNSSubnetOpts eso;
- if(getEDNSSubnetOptsFromString(it->second.content, it->second.size, &eso)) {
+ if(getEDNSSubnetOptsFromString(it->second.values.at(0).content, it->second.values.at(0).size, &eso)) {
*ednssubnet=eso;
foundECS = true;
}
if(needECS || needXPF || (t_pdl && (t_pdl->d_gettag_ffi || t_pdl->d_gettag))) {
try {
- std::map<uint16_t, EDNSOptionView> ednsOptions;
+ EDNSOptionViewMap ednsOptions;
bool xpfFound = false;
dc->d_ecsParsed = true;
dc->d_ecsFound = false;
if(needECS || needXPF || (t_pdl && (t_pdl->d_gettag || t_pdl->d_gettag_ffi))) {
try {
- std::map<uint16_t, EDNSOptionView> ednsOptions;
+ EDNSOptionViewMap ednsOptions;
bool xpfFound = false;
ecsFound = false;
.. class:: EDNSOptionView
- An object that represents a single EDNS option
+ An object that represents the values of a single EDNS option
+
+ .. method:: EDNSOptionView:count()
+ .. versionadded:: 4.2.0
+
+ The number of values for this EDNS option.
+
+ .. method:: EDNSOptionView:getValues()
+ .. versionadded:: 4.2.0
+
+ Return a table of NULL-safe strings values for this EDNS option.
.. attribute:: EDNSOptionView.size
- The size in bytes of the EDNS option.
+ The size in bytes of the first value of this EDNS option.
.. method:: EDNSOptionView:getContent()
- Returns a NULL-safe string object of the EDNS option's content
+ Returns a NULL-safe string object of the first value of this EDNS option.
BOOST_REQUIRE_EQUAL(query.at(pos), 0);
BOOST_REQUIRE(query.at(pos+2) == QType::OPT);
- std::map<uint16_t, EDNSOptionView> options;
+ EDNSOptionViewMap options;
int res = getEDNSOptions(reinterpret_cast<char*>(query.data())+pos+9, questionLen - pos - 9, options);
BOOST_REQUIRE_EQUAL(res, 0);
- /* 3 EDNS options but two of them are EDNS Cookie, so we only keep one */
+ /* 3 EDNS options but two of them are EDNS Cookie, so we only have two entries in the map */
BOOST_CHECK_EQUAL(options.size(), 2);
auto it = options.find(EDNSOptionCode::ECS);
BOOST_REQUIRE(it != options.end());
- BOOST_REQUIRE(it->second.content != nullptr);
- BOOST_REQUIRE_GT(it->second.size, 0);
+ BOOST_REQUIRE_EQUAL(it->second.values.size(), 1);
+ BOOST_REQUIRE(it->second.values.at(0).content != nullptr);
+ BOOST_REQUIRE_GT(it->second.values.at(0).size, 0);
EDNSSubnetOpts eso;
- BOOST_REQUIRE(getEDNSSubnetOptsFromString(it->second.content, it->second.size, &eso));
+ BOOST_REQUIRE(getEDNSSubnetOptsFromString(it->second.values.at(0).content, it->second.values.at(0).size, &eso));
BOOST_CHECK(eso.source == ecs);
it = options.find(EDNSOptionCode::COOKIE);
BOOST_REQUIRE(it != options.end());
- BOOST_REQUIRE(it->second.content != nullptr);
- BOOST_REQUIRE_GT(it->second.size, 0);
+ BOOST_REQUIRE_EQUAL(it->second.values.size(), 2);
+ BOOST_REQUIRE(it->second.values.at(0).content != nullptr);
+ BOOST_REQUIRE_GT(it->second.values.at(0).size, 0);
+ BOOST_REQUIRE(it->second.values.at(1).content != nullptr);
+ BOOST_REQUIRE_GT(it->second.values.at(1).size, 0);
}
static void checkECSOptionValidity(const std::string& sourceStr, uint8_t sourceMask, uint8_t scopeMask)