mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-22 13:33:56 +03:00
Merge pull request #7923 from keszybz/resolved-generic-packet
Resolved generic packet
This commit is contained in:
commit
8f2e968659
@ -1320,7 +1320,9 @@ static void *message_extend_body(
|
||||
m->n_body_parts <= 0 ||
|
||||
m->body_end->sealed ||
|
||||
(padding != ALIGN_TO(m->body_end->size, align) - m->body_end->size) ||
|
||||
(force_inline && m->body_end->size > MEMFD_MIN_SIZE); /* if this must be an inlined extension, let's create a new part if the previous part is large enough to be inlined */
|
||||
(force_inline && m->body_end->size > MEMFD_MIN_SIZE);
|
||||
/* If this must be an inlined extension, let's create a new part if
|
||||
* the previous part is large enough to be inlined. */
|
||||
|
||||
if (add_new_part) {
|
||||
if (padding > 0) {
|
||||
@ -1367,7 +1369,7 @@ static void *message_extend_body(
|
||||
}
|
||||
} else
|
||||
/* Return something that is not NULL and is aligned */
|
||||
p = (uint8_t *) NULL + align;
|
||||
p = (uint8_t*) align;
|
||||
|
||||
m->body_size = end_body;
|
||||
message_extend_containers(m, added);
|
||||
@ -4778,7 +4780,7 @@ _public_ int sd_bus_message_read_array(
|
||||
if (sz == 0)
|
||||
/* Zero length array, let's return some aligned
|
||||
* pointer that is not NULL */
|
||||
p = (uint8_t*) NULL + align;
|
||||
p = (uint8_t*) align;
|
||||
else {
|
||||
r = message_peek_body(m, &m->rindex, align, sz, &p);
|
||||
if (r < 0)
|
||||
|
@ -2129,19 +2129,11 @@ static bool opt_is_good(DnsResourceRecord *rr, bool *rfc6975) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int dns_packet_extract(DnsPacket *p) {
|
||||
static int dns_packet_extract_question(DnsPacket *p, DnsQuestion **ret_question) {
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
|
||||
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
|
||||
_cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder = {};
|
||||
unsigned n, i;
|
||||
int r;
|
||||
|
||||
if (p->extracted)
|
||||
return 0;
|
||||
|
||||
INIT_REWINDER(rewinder, p);
|
||||
dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE);
|
||||
|
||||
n = DNS_PACKET_QDCOUNT(p);
|
||||
if (n > 0) {
|
||||
question = dns_question_new(n);
|
||||
@ -2168,108 +2160,147 @@ int dns_packet_extract(DnsPacket *p) {
|
||||
}
|
||||
}
|
||||
|
||||
*ret_question = question;
|
||||
question = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dns_packet_extract_answer(DnsPacket *p, DnsAnswer **ret_answer) {
|
||||
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
|
||||
unsigned n, i;
|
||||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *previous = NULL;
|
||||
bool bad_opt = false;
|
||||
int r;
|
||||
|
||||
n = DNS_PACKET_RRCOUNT(p);
|
||||
if (n > 0) {
|
||||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *previous = NULL;
|
||||
bool bad_opt = false;
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
answer = dns_answer_new(n);
|
||||
if (!answer)
|
||||
return -ENOMEM;
|
||||
answer = dns_answer_new(n);
|
||||
if (!answer)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
|
||||
bool cache_flush = false;
|
||||
for (i = 0; i < n; i++) {
|
||||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
|
||||
bool cache_flush = false;
|
||||
|
||||
r = dns_packet_read_rr(p, &rr, &cache_flush, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = dns_packet_read_rr(p, &rr, &cache_flush, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Try to reduce memory usage a bit */
|
||||
if (previous)
|
||||
dns_resource_key_reduce(&rr->key, &previous->key);
|
||||
/* Try to reduce memory usage a bit */
|
||||
if (previous)
|
||||
dns_resource_key_reduce(&rr->key, &previous->key);
|
||||
|
||||
if (rr->key->type == DNS_TYPE_OPT) {
|
||||
bool has_rfc6975;
|
||||
if (rr->key->type == DNS_TYPE_OPT) {
|
||||
bool has_rfc6975;
|
||||
|
||||
if (p->opt || bad_opt) {
|
||||
/* Multiple OPT RRs? if so, let's ignore all, because there's something wrong
|
||||
* with the server, and if one is valid we wouldn't know which one. */
|
||||
log_debug("Multiple OPT RRs detected, ignoring all.");
|
||||
bad_opt = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!dns_name_is_root(dns_resource_key_name(rr->key))) {
|
||||
/* If the OPT RR is not owned by the root domain, then it is bad, let's ignore
|
||||
* it. */
|
||||
log_debug("OPT RR is not owned by root domain, ignoring.");
|
||||
bad_opt = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i < DNS_PACKET_ANCOUNT(p) + DNS_PACKET_NSCOUNT(p)) {
|
||||
/* OPT RR is in the wrong section? Some Belkin routers do this. This is a hint
|
||||
* the EDNS implementation is borked, like the Belkin one is, hence ignore
|
||||
* it. */
|
||||
log_debug("OPT RR in wrong section, ignoring.");
|
||||
bad_opt = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!opt_is_good(rr, &has_rfc6975)) {
|
||||
log_debug("Malformed OPT RR, ignoring.");
|
||||
bad_opt = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DNS_PACKET_QR(p)) {
|
||||
/* Additional checks for responses */
|
||||
|
||||
if (!DNS_RESOURCE_RECORD_OPT_VERSION_SUPPORTED(rr)) {
|
||||
/* If this is a reply and we don't know the EDNS version then something
|
||||
* is weird... */
|
||||
log_debug("EDNS version newer that our request, bad server.");
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
if (has_rfc6975) {
|
||||
/* If the OPT RR contains RFC6975 algorithm data, then this is indication that
|
||||
* the server just copied the OPT it got from us (which contained that data)
|
||||
* back into the reply. If so, then it doesn't properly support EDNS, as
|
||||
* RFC6975 makes it very clear that the algorithm data should only be contained
|
||||
* in questions, never in replies. Crappy Belkin routers copy the OPT data for
|
||||
* example, hence let's detect this so that we downgrade early. */
|
||||
log_debug("OPT RR contained RFC6975 data, ignoring.");
|
||||
bad_opt = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
p->opt = dns_resource_record_ref(rr);
|
||||
} else {
|
||||
|
||||
/* According to RFC 4795, section 2.9. only the RRs from the Answer section shall be
|
||||
* cached. Hence mark only those RRs as cacheable by default, but not the ones from the
|
||||
* Additional or Authority sections. */
|
||||
|
||||
r = dns_answer_add(answer, rr, p->ifindex,
|
||||
(i < DNS_PACKET_ANCOUNT(p) ? DNS_ANSWER_CACHEABLE : 0) |
|
||||
(p->protocol == DNS_PROTOCOL_MDNS && !cache_flush ? DNS_ANSWER_SHARED_OWNER : 0));
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (p->opt || bad_opt) {
|
||||
/* Multiple OPT RRs? if so, let's ignore all, because there's
|
||||
* something wrong with the server, and if one is valid we wouldn't
|
||||
* know which one. */
|
||||
log_debug("Multiple OPT RRs detected, ignoring all.");
|
||||
bad_opt = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Remember this RR, so that we potentically can merge it's ->key object with the next RR. Note
|
||||
* that we only do this if we actually decided to keep the RR around. */
|
||||
dns_resource_record_unref(previous);
|
||||
previous = dns_resource_record_ref(rr);
|
||||
if (!dns_name_is_root(dns_resource_key_name(rr->key))) {
|
||||
/* If the OPT RR is not owned by the root domain, then it is bad,
|
||||
* let's ignore it. */
|
||||
log_debug("OPT RR is not owned by root domain, ignoring.");
|
||||
bad_opt = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i < DNS_PACKET_ANCOUNT(p) + DNS_PACKET_NSCOUNT(p)) {
|
||||
/* OPT RR is in the wrong section? Some Belkin routers do this. This
|
||||
* is a hint the EDNS implementation is borked, like the Belkin one
|
||||
* is, hence ignore it. */
|
||||
log_debug("OPT RR in wrong section, ignoring.");
|
||||
bad_opt = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!opt_is_good(rr, &has_rfc6975)) {
|
||||
log_debug("Malformed OPT RR, ignoring.");
|
||||
bad_opt = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DNS_PACKET_QR(p)) {
|
||||
/* Additional checks for responses */
|
||||
|
||||
if (!DNS_RESOURCE_RECORD_OPT_VERSION_SUPPORTED(rr)) {
|
||||
/* If this is a reply and we don't know the EDNS version
|
||||
* then something is weird... */
|
||||
log_debug("EDNS version newer that our request, bad server.");
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
if (has_rfc6975) {
|
||||
/* If the OPT RR contains RFC6975 algorithm data, then this
|
||||
* is indication that the server just copied the OPT it got
|
||||
* from us (which contained that data) back into the reply.
|
||||
* If so, then it doesn't properly support EDNS, as RFC6975
|
||||
* makes it very clear that the algorithm data should only
|
||||
* be contained in questions, never in replies. Crappy
|
||||
* Belkin routers copy the OPT data for example, hence let's
|
||||
* detect this so that we downgrade early. */
|
||||
log_debug("OPT RR contained RFC6975 data, ignoring.");
|
||||
bad_opt = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
p->opt = dns_resource_record_ref(rr);
|
||||
} else {
|
||||
/* According to RFC 4795, section 2.9. only the RRs from the Answer section
|
||||
* shall be cached. Hence mark only those RRs as cacheable by default, but
|
||||
* not the ones from the Additional or Authority sections. */
|
||||
DnsAnswerFlags flags =
|
||||
(i < DNS_PACKET_ANCOUNT(p) ? DNS_ANSWER_CACHEABLE : 0) |
|
||||
(p->protocol == DNS_PROTOCOL_MDNS && !cache_flush ? DNS_ANSWER_SHARED_OWNER : 0);
|
||||
|
||||
r = dns_answer_add(answer, rr, p->ifindex, flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (bad_opt)
|
||||
p->opt = dns_resource_record_unref(p->opt);
|
||||
/* Remember this RR, so that we potentically can merge it's ->key object with the
|
||||
* next RR. Note that we only do this if we actually decided to keep the RR around.
|
||||
*/
|
||||
dns_resource_record_unref(previous);
|
||||
previous = dns_resource_record_ref(rr);
|
||||
}
|
||||
|
||||
if (bad_opt)
|
||||
p->opt = dns_resource_record_unref(p->opt);
|
||||
|
||||
*ret_answer = answer;
|
||||
answer = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_packet_extract(DnsPacket *p) {
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
|
||||
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
|
||||
_cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder = {};
|
||||
int r;
|
||||
|
||||
if (p->extracted)
|
||||
return 0;
|
||||
|
||||
INIT_REWINDER(rewinder, p);
|
||||
dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE);
|
||||
|
||||
r = dns_packet_extract_question(p, &question);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dns_packet_extract_answer(p, &answer);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
p->question = question;
|
||||
question = NULL;
|
||||
|
||||
|
@ -517,9 +517,13 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
|
||||
|
||||
case DNS_TYPE_OPENPGPKEY:
|
||||
default:
|
||||
free(rr->generic.data);
|
||||
if (!rr->unparseable)
|
||||
free(rr->generic.data);
|
||||
}
|
||||
|
||||
if (rr->unparseable)
|
||||
free(rr->generic.data);
|
||||
|
||||
free(rr->wire_format);
|
||||
dns_resource_key_unref(rr->key);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user