resolved: internalize string buffer of dns_resource_record_to_string()

Let's simplify usage and memory management of DnsResourceRecord's
dns_resource_record_to_string() call: cache the formatted string as
part of the object, and return it on subsequent calls, freeing it when
the DnsResourceRecord itself is freed.
This commit is contained in:
Lennart Poettering 2015-12-21 16:31:29 +01:00
parent 0936416a1c
commit 7b50eb2efa
8 changed files with 73 additions and 94 deletions

View file

@ -368,7 +368,7 @@ static int resolve_record(sd_bus *bus, const char *name) {
while ((r = sd_bus_message_enter_container(reply, 'r', "iqqay")) > 0) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
_cleanup_free_ char *s = NULL;
const char *s;
uint16_t c, t;
int ifindex;
const void *d;
@ -402,10 +402,10 @@ static int resolve_record(sd_bus *bus, const char *name) {
if (r < 0)
return log_error_errno(r, "Failed to parse RR.");
r = dns_resource_record_to_string(rr, &s);
if (r < 0) {
s = dns_resource_record_to_string(rr);
if (!s) {
log_error("Failed to format RR.");
return r;
return -ENOMEM;
}
ifname[0] = 0;

View file

@ -657,18 +657,18 @@ int dns_answer_reserve_or_clone(DnsAnswer **a, unsigned n_free) {
void dns_answer_dump(DnsAnswer *answer, FILE *f) {
DnsResourceRecord *rr;
DnsAnswerFlags flags;
int ifindex, r;
int ifindex;
if (!f)
f = stdout;
DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, answer) {
_cleanup_free_ char *t = NULL;
const char *t;
fputc('\t', f);
r = dns_resource_record_to_string(rr, &t);
if (r < 0) {
t = dns_resource_record_to_string(rr);
if (!t) {
log_oom();
continue;
}

View file

@ -938,13 +938,13 @@ void dns_cache_dump(DnsCache *cache, FILE *f) {
DnsCacheItem *j;
LIST_FOREACH(by_key, j, i) {
_cleanup_free_ char *t = NULL;
fputc('\t', f);
if (j->rr) {
r = dns_resource_record_to_string(j->rr, &t);
if (r < 0) {
const char *t;
t = dns_resource_record_to_string(j->rr);
if (!t) {
log_oom();
continue;
}
@ -952,13 +952,14 @@ void dns_cache_dump(DnsCache *cache, FILE *f) {
fputs(t, f);
fputc('\n', f);
} else {
r = dns_resource_key_to_string(j->key, &t);
_cleanup_free_ char *z = NULL;
r = dns_resource_key_to_string(j->key, &z);
if (r < 0) {
log_oom();
continue;
}
fputs(t, f);
fputs(z, f);
fputs(" -- ", f);
fputs(j->type == DNS_CACHE_NODATA ? "NODATA" : "NXDOMAIN", f);
fputc('\n', f);

View file

@ -448,6 +448,7 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
dns_resource_key_unref(rr->key);
}
free(rr->to_string);
free(rr);
return NULL;
@ -763,16 +764,19 @@ static char *format_txt(DnsTxtItem *first) {
return s;
}
int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
_cleanup_free_ char *k = NULL, *t = NULL;
char *s;
int r;
assert(rr);
if (rr->to_string)
return rr->to_string;
r = dns_resource_key_to_string(rr->key, &k);
if (r < 0)
return r;
return NULL;
switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
@ -784,7 +788,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
rr->srv.port,
strna(rr->srv.name));
if (r < 0)
return -ENOMEM;
return NULL;
break;
case DNS_TYPE_PTR:
@ -793,25 +797,25 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
case DNS_TYPE_DNAME:
s = strjoin(k, " ", rr->ptr.name, NULL);
if (!s)
return -ENOMEM;
return NULL;
break;
case DNS_TYPE_HINFO:
s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
if (!s)
return -ENOMEM;
return NULL;
break;
case DNS_TYPE_SPF: /* exactly the same as TXT */
case DNS_TYPE_TXT:
t = format_txt(rr->txt.items);
if (!t)
return -ENOMEM;
return NULL;
s = strjoin(k, " ", t, NULL);
if (!s)
return -ENOMEM;
return NULL;
break;
case DNS_TYPE_A: {
@ -819,22 +823,22 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
if (r < 0)
return r;
return NULL;
s = strjoin(k, " ", x, NULL);
if (!s)
return -ENOMEM;
return NULL;
break;
}
case DNS_TYPE_AAAA:
r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
if (r < 0)
return r;
return NULL;
s = strjoin(k, " ", t, NULL);
if (!s)
return -ENOMEM;
return NULL;
break;
case DNS_TYPE_SOA:
@ -848,7 +852,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
rr->soa.expire,
rr->soa.minimum);
if (r < 0)
return -ENOMEM;
return NULL;
break;
case DNS_TYPE_MX:
@ -857,7 +861,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
rr->mx.priority,
rr->mx.exchange);
if (r < 0)
return -ENOMEM;
return NULL;
break;
case DNS_TYPE_LOC:
@ -870,17 +874,17 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
rr->loc.horiz_pre,
rr->loc.vert_pre);
if (!t)
return -ENOMEM;
return NULL;
s = strjoin(k, " ", t, NULL);
if (!s)
return -ENOMEM;
return NULL;
break;
case DNS_TYPE_DS:
t = hexmem(rr->ds.digest, rr->ds.digest_size);
if (!t)
return -ENOMEM;
return NULL;
r = asprintf(&s, "%s %u %u %u %s",
k,
@ -889,13 +893,13 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
rr->ds.digest_type,
t);
if (r < 0)
return -ENOMEM;
return NULL;
break;
case DNS_TYPE_SSHFP:
t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
if (!t)
return -ENOMEM;
return NULL;
r = asprintf(&s, "%s %u %u %s",
k,
@ -903,7 +907,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
rr->sshfp.fptype,
t);
if (r < 0)
return -ENOMEM;
return NULL;
break;
case DNS_TYPE_DNSKEY: {
@ -913,7 +917,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
t = base64mem(rr->dnskey.key, rr->dnskey.key_size);
if (!t)
return -ENOMEM;
return NULL;
r = asprintf(&s, "%s %u %u %.*s%.*u %s",
k,
@ -923,7 +927,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
alg ? 0 : 1, alg ? 0u : (unsigned) rr->dnskey.algorithm,
t);
if (r < 0)
return -ENOMEM;
return NULL;
break;
}
@ -936,15 +940,15 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
t = base64mem(rr->rrsig.signature, rr->rrsig.signature_size);
if (!t)
return -ENOMEM;
return NULL;
r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration);
if (r < 0)
return r;
return NULL;
r = format_timestamp_dns(inception, sizeof(inception), rr->rrsig.inception);
if (r < 0)
return r;
return NULL;
/* TYPE?? follows
* http://tools.ietf.org/html/rfc3597#section-5 */
@ -963,21 +967,21 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
rr->rrsig.signer,
t);
if (r < 0)
return -ENOMEM;
return NULL;
break;
}
case DNS_TYPE_NSEC:
t = format_types(rr->nsec.types);
if (!t)
return -ENOMEM;
return NULL;
r = asprintf(&s, "%s %s %s",
k,
rr->nsec.next_domain_name,
t);
if (r < 0)
return -ENOMEM;
return NULL;
break;
case DNS_TYPE_NSEC3: {
@ -986,16 +990,16 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
if (rr->nsec3.salt_size > 0) {
salt = hexmem(rr->nsec3.salt, rr->nsec3.salt_size);
if (!salt)
return -ENOMEM;
return NULL;
}
hash = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false);
if (!hash)
return -ENOMEM;
return NULL;
t = format_types(rr->nsec3.types);
if (!t)
return -ENOMEM;
return NULL;
r = asprintf(&s, "%s %"PRIu8" %"PRIu8" %"PRIu16" %s %s %s",
k,
@ -1006,7 +1010,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
hash,
t);
if (r < 0)
return -ENOMEM;
return NULL;
break;
}
@ -1014,16 +1018,16 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
default:
t = hexmem(rr->generic.data, rr->generic.size);
if (!t)
return -ENOMEM;
return NULL;
r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.size, t);
if (r < 0)
return -ENOMEM;
return NULL;
break;
}
*ret = s;
return 0;
rr->to_string = s;
return s;
}
int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical) {

View file

@ -95,6 +95,7 @@ struct DnsTxtItem {
struct DnsResourceRecord {
unsigned n_ref;
DnsResourceKey *key;
char *to_string;
uint32_t ttl;
bool unparseable:1;
bool wire_format_canonical:1;
@ -253,7 +254,7 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr);
int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name);
int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name);
int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b);
int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret);
const char* dns_resource_record_to_string(DnsResourceRecord *rr);
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsResourceRecord*, dns_resource_record_unref);
int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical);

View file

@ -1906,12 +1906,7 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) {
if (r < 0)
return r;
if (log_get_max_level() >= LOG_DEBUG) {
_cleanup_free_ char *rrs = NULL;
(void) dns_resource_record_to_string(rr, &rrs);
log_debug("Looking at %s: %s", rrs ? strstrip(rrs) : "???", dnssec_result_to_string(result));
}
log_debug("Looking at %s: %s", strna(dns_resource_record_to_string(rr)), dnssec_result_to_string(result));
if (result == DNSSEC_VALIDATED) {

View file

@ -471,15 +471,12 @@ return_empty:
}
void dns_zone_item_conflict(DnsZoneItem *i) {
_cleanup_free_ char *pretty = NULL;
assert(i);
if (!IN_SET(i->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_VERIFYING, DNS_ZONE_ITEM_ESTABLISHED))
return;
dns_resource_record_to_string(i->rr, &pretty);
log_info("Detected conflict on %s", strna(pretty));
log_info("Detected conflict on %s", strna(dns_resource_record_to_string(i->rr)));
dns_zone_item_probe_stop(i);
@ -492,8 +489,6 @@ void dns_zone_item_conflict(DnsZoneItem *i) {
}
void dns_zone_item_notify(DnsZoneItem *i) {
_cleanup_free_ char *pretty = NULL;
assert(i);
assert(i->probe_transaction);
@ -530,15 +525,13 @@ void dns_zone_item_notify(DnsZoneItem *i) {
log_debug("Got a successful probe reply, but peer has lexicographically lower IP address and thus lost.");
}
dns_resource_record_to_string(i->rr, &pretty);
log_debug("Record %s successfully probed.", strna(pretty));
log_debug("Record %s successfully probed.", strna(dns_resource_record_to_string(i->rr)));
dns_zone_item_probe_stop(i);
i->state = DNS_ZONE_ITEM_ESTABLISHED;
}
static int dns_zone_item_verify(DnsZoneItem *i) {
_cleanup_free_ char *pretty = NULL;
int r;
assert(i);
@ -546,8 +539,7 @@ static int dns_zone_item_verify(DnsZoneItem *i) {
if (i->state != DNS_ZONE_ITEM_ESTABLISHED)
return 0;
dns_resource_record_to_string(i->rr, &pretty);
log_debug("Verifying RR %s", strna(pretty));
log_debug("Verifying RR %s", strna(dns_resource_record_to_string(i->rr)));
i->state = DNS_ZONE_ITEM_VERIFYING;
r = dns_zone_item_probe_start(i);
@ -632,7 +624,6 @@ void dns_zone_verify_all(DnsZone *zone) {
void dns_zone_dump(DnsZone *zone, FILE *f) {
Iterator iterator;
DnsZoneItem *i;
int r;
if (!zone)
return;
@ -644,10 +635,10 @@ void dns_zone_dump(DnsZone *zone, FILE *f) {
DnsZoneItem *j;
LIST_FOREACH(by_key, j, i) {
_cleanup_free_ char *t = NULL;
const char *t;
r = dns_resource_record_to_string(j->rr, &t);
if (r < 0) {
t = dns_resource_record_to_string(j->rr);
if (!t) {
log_oom();
continue;
}

View file

@ -56,7 +56,6 @@ static void test_dnssec_verify_rrset2(void) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *nsec = NULL, *rrsig = NULL, *dnskey = NULL;
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
_cleanup_free_ char *x = NULL, *y = NULL, *z = NULL;
DnssecResult result;
nsec = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC, "nasa.gov");
@ -77,8 +76,7 @@ static void test_dnssec_verify_rrset2(void) {
assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_DNSKEY) >= 0);
assert_se(bitmap_set(nsec->nsec.types, 65534) >= 0);
assert_se(dns_resource_record_to_string(nsec, &x) >= 0);
log_info("NSEC: %s", x);
log_info("NSEC: %s", strna(dns_resource_record_to_string(nsec)));
rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV.");
assert_se(rrsig);
@ -96,8 +94,7 @@ static void test_dnssec_verify_rrset2(void) {
rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size);
assert_se(rrsig->rrsig.signature);
assert_se(dns_resource_record_to_string(rrsig, &y) >= 0);
log_info("RRSIG: %s", y);
log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig)));
dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV");
assert_se(dnskey);
@ -109,8 +106,7 @@ static void test_dnssec_verify_rrset2(void) {
dnskey->dnskey.key = memdup(dnskey_blob, sizeof(dnskey_blob));
assert_se(dnskey->dnskey.key);
assert_se(dns_resource_record_to_string(dnskey, &z) >= 0);
log_info("DNSKEY: %s", z);
log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey));
assert_se(dnssec_key_match_rrsig(nsec->key, rrsig) > 0);
@ -152,7 +148,6 @@ static void test_dnssec_verify_rrset(void) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *a = NULL, *rrsig = NULL, *dnskey = NULL;
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
_cleanup_free_ char *x = NULL, *y = NULL, *z = NULL;
DnssecResult result;
a = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, "nAsA.gov");
@ -160,8 +155,7 @@ static void test_dnssec_verify_rrset(void) {
a->a.in_addr.s_addr = inet_addr("52.0.14.116");
assert_se(dns_resource_record_to_string(a, &x) >= 0);
log_info("A: %s", x);
log_info("A: %s", strna(dns_resource_record_to_string(a)));
rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV.");
assert_se(rrsig);
@ -179,8 +173,7 @@ static void test_dnssec_verify_rrset(void) {
rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size);
assert_se(rrsig->rrsig.signature);
assert_se(dns_resource_record_to_string(rrsig, &y) >= 0);
log_info("RRSIG: %s", y);
log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig)));
dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV");
assert_se(dnskey);
@ -192,8 +185,7 @@ static void test_dnssec_verify_rrset(void) {
dnskey->dnskey.key = memdup(dnskey_blob, sizeof(dnskey_blob));
assert_se(dnskey->dnskey.key);
assert_se(dns_resource_record_to_string(dnskey, &z) >= 0);
log_info("DNSKEY: %s", z);
log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey));
assert_se(dnssec_key_match_rrsig(a->key, rrsig) > 0);
@ -239,7 +231,6 @@ static void test_dnssec_verify_dns_key(void) {
};
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds1 = NULL, *ds2 = NULL;
_cleanup_free_ char *a = NULL, *b = NULL, *c = NULL;
/* The two DS RRs in effect for nasa.gov on 2015-12-01. */
ds1 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "nasa.gov");
@ -252,8 +243,7 @@ static void test_dnssec_verify_dns_key(void) {
ds1->ds.digest = memdup(ds1_fprint, ds1->ds.digest_size);
assert_se(ds1->ds.digest);
assert_se(dns_resource_record_to_string(ds1, &a) >= 0);
log_info("DS1: %s", a);
log_info("DS1: %s", strna(dns_resource_record_to_string(ds1)));
ds2 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "NASA.GOV");
assert_se(ds2);
@ -265,8 +255,7 @@ static void test_dnssec_verify_dns_key(void) {
ds2->ds.digest = memdup(ds2_fprint, ds2->ds.digest_size);
assert_se(ds2->ds.digest);
assert_se(dns_resource_record_to_string(ds2, &b) >= 0);
log_info("DS2: %s", b);
log_info("DS2: %s", strna(dns_resource_record_to_string(ds2)));
dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nasa.GOV");
assert_se(dnskey);
@ -278,8 +267,7 @@ static void test_dnssec_verify_dns_key(void) {
dnskey->dnskey.key = memdup(dnskey_blob, sizeof(dnskey_blob));
assert_se(dnskey->dnskey.key);
assert_se(dns_resource_record_to_string(dnskey, &c) >= 0);
log_info("DNSKEY: %s", c);
log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey));
assert_se(dnssec_verify_dnskey(dnskey, ds1) > 0);
@ -310,8 +298,8 @@ static void test_dnssec_nsec3_hash(void) {
static const uint8_t salt[] = { 0xB0, 0x1D, 0xFA, 0xCE };
static const uint8_t next_hashed_name[] = { 0x84, 0x10, 0x26, 0x53, 0xc9, 0xfa, 0x4d, 0x85, 0x6c, 0x97, 0x82, 0xe2, 0x8f, 0xdf, 0x2d, 0x5e, 0x87, 0x69, 0xc4, 0x52 };
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
_cleanup_free_ char *a = NULL, *b = NULL;
uint8_t h[DNSSEC_HASH_SIZE_MAX];
_cleanup_free_ char *b = NULL;
int k;
/* The NSEC3 RR for eurid.eu on 2015-12-14. */
@ -328,8 +316,7 @@ static void test_dnssec_nsec3_hash(void) {
assert_se(rr->nsec3.next_hashed_name);
rr->nsec3.next_hashed_name_size = sizeof(next_hashed_name);
assert_se(dns_resource_record_to_string(rr, &a) >= 0);
log_info("NSEC3: %s", a);
log_info("NSEC3: %s", strna(dns_resource_record_to_string(rr)));
k = dnssec_nsec3_hash(rr, "eurid.eu", &h);
assert_se(k >= 0);