// do we even have a response?
if (d_cname.empty() &&
d_rawResponses.empty() &&
+ // make sure pre-forged response is greater than sizeof(dnsheader)
+ (d_raw.size() < sizeof(dnsheader)) &&
d_types.count(qtype) == 0) {
return Action::None;
}
+ if (d_raw.size() >= sizeof(dnsheader)) {
+ auto id = dq->getHeader()->id;
+ dq->getMutableData() = std::move(d_raw);
+ dq->getHeader()->id = id;
+ return Action::HeaderModify;
+ }
vector<ComboAddress> addrs;
vector<std::string> rawResponses;
unsigned int totrdatalen = 0;
return ret;
});
+ luaCtx.writeFunction("SpoofPacketAction", [](const std::string& response, size_t len) {
+ if (len < sizeof(dnsheader)) {
+ throw std::runtime_error(std::string("SpoofPacketAction: given packet len is too small"));
+ }
+ auto ret = std::shared_ptr<DNSAction>(new SpoofAction(response.c_str(), len));
+ return ret;
+ });
+
luaCtx.writeFunction("DropAction", []() {
return std::shared_ptr<DNSAction>(new DropAction);
});
void dnsdist_ffi_dnsquestion_spoof_raw(dnsdist_ffi_dnsquestion_t* dq, const dnsdist_ffi_raw_value_t* values, size_t valuesCount) __attribute__ ((visibility ("default")));
// the content of values should contain raw IPv4 or IPv6 addresses in network byte-order
void dnsdist_ffi_dnsquestion_spoof_addrs(dnsdist_ffi_dnsquestion_t* dq, const dnsdist_ffi_raw_value_t* values, size_t valuesCount) __attribute__ ((visibility ("default")));
+// spoof raw response. will just replace qid to match question
+void dnsdist_ffi_dnsquestion_spoof_packet(dnsdist_ffi_dnsquestion_t* dq, const char* rawresponse, size_t len) __attribute__ ((visibility ("default")));
typedef struct dnsdist_ffi_servers_list_t dnsdist_ffi_servers_list_t;
typedef struct dnsdist_ffi_server_t dnsdist_ffi_server_t;
(_, receivedResponse) = sender(query, response=None, useQueue=False)
self.assertTrue(receivedResponse)
self.assertEqual(expectedResponseAfterwards, receivedResponse)
+
+class TestSpoofingLuaSpoofPacket(DNSDistTest):
+
+ _config_template = """
+ local ffi = require("ffi")
+
+ function spoofpacket(dq)
+ -- REFUSED answer
+ local rawResponse="\\000\\000\\129\\133\\000\\001\\000\\000\\000\\000\\000\\000\\014lua\\045raw\\045packet\\012ffi\\045spoofing\\005tests\\008powerdns\\003com\\000\\000\\001\\000\\001"
+ local qtype = ffi.C.dnsdist_ffi_dnsquestion_get_qtype(dq)
+ ffi.C.dnsdist_ffi_dnsquestion_spoof_packet(dq, rawResponse, string.len(rawResponse))
+ return DNSAction.HeaderModify
+ end
+
+ addAction("lua-raw-packet.ffi-spoofing.tests.powerdns.com.", LuaFFIAction(spoofpacket))
+ local otherResponse="\\000\\000\\129\\133\\000\\001\\000\\000\\000\\000\\000\\000\\014lua\\045raw\\045packet\\008spoofing\\005tests\\008powerdns\\003com\\000\\000\\001\\000\\001"
+ addAction("lua-raw-packet.spoofing.tests.powerdns.com.", SpoofPacketAction(otherResponse, string.len(otherResponse)))
+ newServer{address="127.0.0.1:%s"}
+ """
+ _verboseMode = True
+
+ def testLuaFFISpoofPacket(self):
+ """
+ Spoofing via Lua FFI: Spoof raw response via Lua FFI
+ """
+ name = 'lua-raw-packet.ffi-spoofing.tests.powerdns.com.'
+
+ #
+ query = dns.message.make_query(name, 'A', 'IN')
+ expectedResponse = dns.message.make_response(query)
+ expectedResponse.flags |= dns.flags.RA
+ expectedResponse.set_rcode(dns.rcode.REFUSED)
+
+ for method in ("sendUDPQuery", "sendTCPQuery"):
+ sender = getattr(self, method)
+ (_, receivedResponse) = sender(query, response=None, useQueue=False)
+ self.assertTrue(receivedResponse)
+ self.assertEqual(expectedResponse, receivedResponse)
+
+ def testLuaSpoofPacket(self):
+ """
+ Spoofing via Lua : Spoof raw response via Lua
+ """
+ name = 'lua-raw-packet.spoofing.tests.powerdns.com.'
+
+ #
+ query = dns.message.make_query(name, 'A', 'IN')
+ expectedResponse = dns.message.make_response(query)
+ expectedResponse.flags |= dns.flags.RA
+ expectedResponse.set_rcode(dns.rcode.REFUSED)
+
+ for method in ("sendUDPQuery", "sendTCPQuery"):
+ sender = getattr(self, method)
+ (_, receivedResponse) = sender(query, response=None, useQueue=False)
+ self.assertTrue(receivedResponse)
+ self.assertEqual(expectedResponse, receivedResponse)