1
0
mirror of https://github.com/systemd/systemd.git synced 2024-10-31 16:21:26 +03:00

Merge pull request #18605 from poettering/suppress-repeated-stub

resolved: filter repeated stub queries
This commit is contained in:
Lennart Poettering 2021-02-15 23:06:37 +01:00 committed by GitHub
commit 0886999416
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 75 additions and 0 deletions

View File

@ -382,6 +382,13 @@ DnsQuery *dns_query_free(DnsQuery *q) {
varlink_unref(q->varlink_request);
}
if (q->request_packet)
hashmap_remove_value(q->stub_listener_extra ?
q->stub_listener_extra->queries_by_packet :
q->manager->stub_queries_by_packet,
q->request_packet,
q);
dns_packet_unref(q->request_packet);
dns_answer_unref(q->reply_answer);
dns_answer_unref(q->reply_authoritative);

View File

@ -82,6 +82,8 @@ DnsStubListenerExtra *dns_stub_listener_extra_free(DnsStubListenerExtra *p) {
p->udp_event_source = sd_event_source_unref(p->udp_event_source);
p->tcp_event_source = sd_event_source_unref(p->tcp_event_source);
hashmap_free(p->queries_by_packet);
return mfree(p);
}
@ -94,6 +96,47 @@ uint16_t dns_stub_listener_extra_port(DnsStubListenerExtra *p) {
return 53;
}
static void stub_packet_hash_func(const DnsPacket *p, struct siphash *state) {
assert(p);
siphash24_compress(&p->protocol, sizeof(p->protocol), state);
siphash24_compress(&p->family, sizeof(p->family), state);
siphash24_compress(&p->sender, sizeof(p->sender), state);
siphash24_compress(&p->ipproto, sizeof(p->ipproto), state);
siphash24_compress(&p->sender_port, sizeof(p->sender_port), state);
siphash24_compress(DNS_PACKET_HEADER(p), sizeof(DnsPacketHeader), state);
/* We don't bother hashing the full packet here, just the header */
}
static int stub_packet_compare_func(const DnsPacket *x, const DnsPacket *y) {
int r;
r = CMP(x->protocol, y->protocol);
if (r != 0)
return r;
r = CMP(x->family, y->family);
if (r != 0)
return r;
r = memcmp(&x->sender, &y->sender, sizeof(x->sender));
if (r != 0)
return r;
r = CMP(x->ipproto, y->ipproto);
if (r != 0)
return r;
r = CMP(x->sender_port, y->sender_port);
if (r != 0)
return r;
return memcmp(DNS_PACKET_HEADER(x), DNS_PACKET_HEADER(y), sizeof(DnsPacketHeader));
}
DEFINE_HASH_OPS(stub_packet_hash_ops, DnsPacket, stub_packet_hash_func, stub_packet_compare_func);
static int dns_stub_collect_answer_by_question(
DnsAnswer **reply,
DnsAnswer *answer,
@ -685,6 +728,8 @@ static int dns_stub_stream_complete(DnsStream *s, int error) {
static void dns_stub_process_query(Manager *m, DnsStubListenerExtra *l, DnsStream *s, DnsPacket *p) {
_cleanup_(dns_query_freep) DnsQuery *q = NULL;
Hashmap **queries_by_packet;
DnsQuery *existing;
int r;
assert(m);
@ -703,6 +748,13 @@ static void dns_stub_process_query(Manager *m, DnsStubListenerExtra *l, DnsStrea
return;
}
queries_by_packet = l ? &l->queries_by_packet : &m->stub_queries_by_packet;
existing = hashmap_get(*queries_by_packet, p);
if (existing && dns_packet_equal(existing->request_packet, p)) {
log_debug("Got repeat packet from client, ignoring.");
return;
}
r = dns_packet_extract(p);
if (r < 0) {
log_debug_errno(r, "Failed to extract resources from incoming packet, ignoring packet: %m");
@ -735,6 +787,12 @@ static void dns_stub_process_query(Manager *m, DnsStubListenerExtra *l, DnsStrea
return;
}
r = hashmap_ensure_allocated(queries_by_packet, &stub_packet_hash_ops);
if (r < 0) {
log_oom();
return;
}
if (DNS_PACKET_DO(p) && DNS_PACKET_CD(p)) {
log_debug("Got request with DNSSEC checking disabled, enabling bypass logic.");
@ -774,6 +832,11 @@ static void dns_stub_process_query(Manager *m, DnsStubListenerExtra *l, DnsStrea
assert(r > 0);
}
/* Add the query to the hash table we use to determine repeat packets now. We don't care about
* failures here, since in the worst case we'll not recognize duplicate incoming requests, which
* isn't particularly bad. */
(void) hashmap_put(*queries_by_packet, q->request_packet, q);
r = dns_query_go(q);
if (r < 0) {
log_error_errno(r, "Failed to start query: %m");

View File

@ -27,6 +27,8 @@ struct DnsStubListenerExtra {
sd_event_source *udp_event_source;
sd_event_source *tcp_event_source;
Hashmap *queries_by_packet;
};
extern const struct hash_ops dns_stub_listener_extra_hash_ops;

View File

@ -739,6 +739,8 @@ Manager *manager_free(Manager *m) {
while (m->dns_queries)
dns_query_free(m->dns_queries);
m->stub_queries_by_packet = hashmap_free(m->stub_queries_by_packet);
dns_scope_free(m->unicast_scope);
/* At this point only orphaned streams should remain. All others should have been freed already by their

View File

@ -59,6 +59,7 @@ struct Manager {
Hashmap *dns_transactions;
LIST_HEAD(DnsQuery, dns_queries);
unsigned n_dns_queries;
Hashmap *stub_queries_by_packet;
LIST_HEAD(DnsStream, dns_streams);
unsigned n_dns_streams[_DNS_STREAM_TYPE_MAX];