Browse Source

[Fix] Check remain before processing TXT records

pull/3803/head
Vsevolod Stakhov 5 years ago
parent
commit
2043543894
  1. 94
      contrib/librdns/parse.c

94
contrib/librdns/parse.c

@ -263,7 +263,8 @@ rdns_parse_rr (struct rdns_resolver *resolver,
return -1;
}
if (*remain < (int)sizeof (uint16_t) * 6) {
rdns_info ("stripped dns reply: %d bytes remain", *remain);
rdns_info ("stripped dns reply: %d bytes remain; domain %s", *remain,
rep->requested_name);
return -1;
}
GET16 (type);
@ -282,7 +283,7 @@ rdns_parse_rr (struct rdns_resolver *resolver,
parsed = true;
}
else {
rdns_info ("corrupted A record");
rdns_info ("corrupted A record; domain: %s", rep->requested_name);
return -1;
}
break;
@ -294,14 +295,14 @@ rdns_parse_rr (struct rdns_resolver *resolver,
parsed = true;
}
else {
rdns_info ("corrupted AAAA record");
rdns_info ("corrupted AAAA record; domain %s", rep->requested_name);
return -1;
}
break;
case DNS_T_PTR:
if (! rdns_parse_labels (resolver, in, &elt->content.ptr.name, &p,
rep, remain, true)) {
rdns_info ("invalid labels in PTR record");
rdns_info ("invalid labels in PTR record; domain %s", rep->requested_name);
return -1;
}
parsed = true;
@ -309,7 +310,7 @@ rdns_parse_rr (struct rdns_resolver *resolver,
case DNS_T_NS:
if (! rdns_parse_labels (resolver, in, &elt->content.ns.name, &p,
rep, remain, true)) {
rdns_info ("invalid labels in NS record");
rdns_info ("invalid labels in NS record; domain %s", rep->requested_name);
return -1;
}
parsed = true;
@ -317,60 +318,74 @@ rdns_parse_rr (struct rdns_resolver *resolver,
case DNS_T_SOA:
if (! rdns_parse_labels (resolver, in, &elt->content.soa.mname, &p,
rep, remain, true)) {
rdns_info ("invalid labels in NS record");
rdns_info ("invalid labels in SOA record; domain %s", rep->requested_name);
return -1;
}
if (! rdns_parse_labels (resolver, in, &elt->content.soa.admin, &p,
rep, remain, true)) {
rdns_info ("invalid labels in NS record");
rdns_info ("invalid labels in SOA record; domain %s", rep->requested_name);
return -1;
}
if (*remain >= sizeof(int32_t) * 5) {
GET32 (elt->content.soa.serial);
GET32 (elt->content.soa.refresh);
GET32 (elt->content.soa.retry);
GET32 (elt->content.soa.expire);
GET32 (elt->content.soa.minimum);
}
else {
rdns_info ("invalid data in SOA record; domain %s", rep->requested_name);
return -1;
}
GET32 (elt->content.soa.serial);
GET32 (elt->content.soa.refresh);
GET32 (elt->content.soa.retry);
GET32 (elt->content.soa.expire);
GET32 (elt->content.soa.minimum);
parsed = true;
break;
case DNS_T_MX:
GET16 (elt->content.mx.priority);
if (! rdns_parse_labels (resolver, in, &elt->content.mx.name, &p,
rep, remain, true)) {
rdns_info ("invalid labels in MX record");
rdns_info ("invalid labels in MX record; domain %s", rep->requested_name);
return -1;
}
parsed = true;
break;
case DNS_T_TXT:
case DNS_T_SPF:
elt->content.txt.data = malloc (datalen + 1);
if (elt->content.txt.data == NULL) {
rdns_err ("failed to allocate %d bytes for TXT record", (int)datalen + 1);
return -1;
}
/* Now we should compose data from parts */
copied = 0;
parts = 0;
while (copied + parts < datalen) {
txtlen = *p;
if (txtlen + copied + parts <= datalen) {
parts ++;
memcpy (elt->content.txt.data + copied, p + 1, txtlen);
copied += txtlen;
p += txtlen + 1;
*remain -= txtlen + 1;
if (datalen <= *remain) {
elt->content.txt.data = malloc(datalen + 1);
if (elt->content.txt.data == NULL) {
rdns_err ("failed to allocate %d bytes for TXT record; domain %s",
(int) datalen + 1, rep->requested_name);
return -1;
}
else {
break;
/* Now we should compose data from parts */
copied = 0;
parts = 0;
while (copied + parts < datalen && *remain > 0) {
txtlen = *p;
if (txtlen + copied + parts <= datalen && *remain >= txtlen + 1) {
parts++;
memcpy (elt->content.txt.data + copied, p + 1, txtlen);
copied += txtlen;
p += txtlen + 1;
*remain -= txtlen + 1;
}
else {
break;
}
}
*(elt->content.txt.data + copied) = '\0';
parsed = true;
elt->type = RDNS_REQUEST_TXT;
}
else {
rdns_info ("stripped data in TXT record (%d bytes available, %d requested); "
"domain %s", (int)*remain, (int)datalen, rep->requested_name);
return -1;
}
*(elt->content.txt.data + copied) = '\0';
parsed = true;
elt->type = RDNS_REQUEST_TXT;
break;
case DNS_T_SRV:
if (p - *pos > (int)(*remain - sizeof (uint16_t) * 3)) {
rdns_info ("stripped dns reply while reading SRV record");
rdns_info ("stripped dns reply while reading SRV record; domain %s", rep->requested_name);
return -1;
}
GET16 (elt->content.srv.priority);
@ -378,14 +393,14 @@ rdns_parse_rr (struct rdns_resolver *resolver,
GET16 (elt->content.srv.port);
if (! rdns_parse_labels (resolver, in, &elt->content.srv.target,
&p, rep, remain, true)) {
rdns_info ("invalid labels in SRV record");
rdns_info ("invalid labels in SRV record; domain %s", rep->requested_name);
return -1;
}
parsed = true;
break;
case DNS_T_TLSA:
if (p - *pos > (int)(*remain - sizeof (uint8_t) * 3) || datalen <= 3) {
rdns_info ("stripped dns reply while reading TLSA record");
rdns_info ("stripped dns reply while reading TLSA record; domain %s", rep->requested_name);
return -1;
}
GET8 (elt->content.tlsa.usage);
@ -394,7 +409,8 @@ rdns_parse_rr (struct rdns_resolver *resolver,
datalen -= 3;
elt->content.tlsa.data = malloc (datalen);
if (elt->content.tlsa.data == NULL) {
rdns_err ("failed to allocate %d bytes for TLSA record", (int)datalen + 1);
rdns_err ("failed to allocate %d bytes for TLSA record; domain %s",
(int)datalen + 1, rep->requested_name);
return -1;
}
elt->content.tlsa.datalen = datalen;
@ -409,7 +425,7 @@ rdns_parse_rr (struct rdns_resolver *resolver,
*remain -= datalen;
break;
default:
rdns_debug ("unexpected RR type: %d", type);
rdns_debug ("unexpected RR type: %d; domain %s", type, rep->requested_name);
p += datalen;
*remain -= datalen;
break;

Loading…
Cancel
Save