* QType (QTypeRule)
* RegexRule on query name
* Packet requests DNSSEC processing
+ * Query received over UDP or TCP
A special rule is `AndRule{rule1, rule2}`, which only matches if all of its subrules match.
* a QTypeRule
* a RegexRule
* a SuffixMatchNodeRule
+ * a TCPRule
A convenience function `makeRule()` is supplied which will make a NetmaskGroupRule for you or a SuffixMatchNodeRule
depending on how you call it. `makeRule("0.0.0.0/0")` will for example match all IPv4 traffic, `makeRule{"be","nl","lu"}` will
ANY or whatever to TC
---------------------
-The `blockFilter()` also gets passed read/writable copy of the DNS Header.
+The `blockFilter()` also gets passed read/writable copy of the DNS Header,
+via `dq.dh`.
If you invoke setQR(1) on that, `dnsdist` knows you turned the packet into
a response, and will send the answer directly to the original client.
* `QTypeRule(qtype)`: matches queries with the specified qtype
* `RegexRule(regex)`: matches the query name against the supplied regex
* `SuffixMatchNodeRule()`: matches based on a group of domain suffixes for rapid testing of membership
+ * `TCPRule(tcp)`: matches question received over TCP if `tcp` is true, over UDP otherwise
* Rule management related:
* `showRules()`: show all defined rules (Pool, Block, QPS, addAnyTCRule)
* `rmRule(n)`: remove rule n
* `SpoofCNAMEAction()`: forge a response with the specified CNAME value
* `TCAction()`: create answer to query with TC and RD bits set, to move to TCP/IP
* Specialist rule generators
- * `addAnyTCRule()`: generate TC=1 answers to ANY queries, moving them to TCP
+ * `addAnyTCRule()`: generate TC=1 answers to ANY queries received over UDP, moving them to TCP
* `addDomainSpoof(domain, ip[, ip6])`: generate answers for A queries using the ip parameter (AAAA if ip is an IPv6). If ip6 is supplied, generate answers for AAAA queries too
* `addDomainCNAMESpoof(domain, cname)`: generate CNAME answers for queries using the specified value
* `addDisableValidationRule(domain)`: set the CD flags to 1 for all queries matching the specified domain
} );
g_lua.writeFunction("makeRule", makeRule);
+
g_lua.writeFunction("addAnyTCRule", []() {
setLuaSideEffect();
auto rules=g_rulactions.getCopy();
- rules.push_back({ std::make_shared<QTypeRule>(0xff), std::make_shared<TCAction>()});
+ std::vector<pair<int, shared_ptr<DNSRule> >> v;
+ v.push_back({1, std::make_shared<QTypeRule>(0xff)});
+ v.push_back({2, std::make_shared<TCPRule>(false)});
+ rules.push_back({ std::shared_ptr<DNSRule>(new AndRule(v)), std::make_shared<TCAction>()});
g_rulactions.setState(rules);
});
return std::shared_ptr<DNSRule>(new AndRule(a));
});
+ g_lua.writeFunction("TCPRule", [](bool tcp) {
+ return std::shared_ptr<DNSRule>(new TCPRule(tcp));
+ });
g_lua.writeFunction("addAction", [](luadnsrule_t var, std::shared_ptr<DNSAction> ea)
{
uint16_t d_qtype;
};
+class TCPRule : public DNSRule
+{
+public:
+ TCPRule(bool tcp): d_tcp(tcp)
+ {
+ }
+ bool matches(const DNSQuestion* dq) const override
+ {
+ return dq->tcp == d_tcp;
+ }
+ string toString() const override
+ {
+ return (d_tcp ? "TCP" : "UDP");
+ }
+private:
+ bool d_tcp;
+};
+
class DropAction : public DNSAction
{
public:
if not answered:
# unexpected query, or health check
response = dns.message.make_response(request)
+ rrset = None
if request.question[0].rdclass == dns.rdataclass.IN:
if request.question[0].rdtype == dns.rdatatype.A:
rrset = dns.rrset.from_text(request.question[0].name,
if not answered:
# unexpected query, or health check
response = dns.message.make_response(request)
+ rrset = None
if request.question[0].rdclass == dns.rdataclass.IN:
if request.question[0].rdtype == dns.rdatatype.A:
rrset = dns.rrset.from_text(request.question[0].name,
dnsdist is configured to reply with TC to ANY queries,
send an ANY query and check the result.
+ It should be truncated over UDP, not over TCP.
"""
name = 'any.tests.powerdns.com.'
query = dns.message.make_query(name, 'ANY', 'IN')
receivedResponse.id = expectedResponse.id
self.assertEquals(receivedResponse, expectedResponse)
- (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
- receivedResponse.id = expectedResponse.id
- self.assertEquals(receivedResponse, expectedResponse)
+ response = dns.message.make_response(query)
+ rrset = dns.rrset.from_text('any.tests.powerdns.com.',
+ 3600,
+ dns.rdataclass.IN,
+ dns.rdatatype.A,
+ '127.0.0.1')
+
+ response.answer.append(rrset)
+
+ (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
+ self.assertTrue(receivedQuery)
+ self.assertTrue(receivedResponse)
+ receivedQuery.id = query.id
+ receivedResponse.id = response.id
+ self.assertEquals(query, receivedQuery)
+ self.assertEquals(receivedResponse, response)
def testTruncateTC(self):
"""