#include "config.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#include "rdata.h"
#include "zonec.h"
#include "query.h"
#include "dname.h"
lookup_table_type dns_certificate_types[] = {
{ 1, "PKIX" },
{ 2, "SPKI" },
{ 3, "PGP" },
{ 4, "IPKIX" },
{ 5, "ISPKI" },
{ 6, "IPGP" },
{ 7, "ACPKIX" },
{ 8, "IACPKIX" },
{ 253, "URI" },
{ 254, "OID" },
{ 0, NULL }
};
lookup_table_type dns_algorithms[] = {
{ 1, "RSAMD5" },
{ 2, "DH" },
{ 3, "DSA" },
{ 4, "ECC" },
{ 5, "RSASHA1" },
{ 6, "DSA-NSEC3-SHA1" },
{ 7, "RSASHA1-NSEC3-SHA1" },
{ 8, "RSASHA256" },
{ 10, "RSASHA512" },
{ 12, "ECC-GOST" },
{ 13, "ECDSAP256SHA256" },
{ 14, "ECDSAP384SHA384" },
{ 15, "ED25519" },
{ 16, "ED448" },
{ 252, "INDIRECT" },
{ 253, "PRIVATEDNS" },
{ 254, "PRIVATEOID" },
{ 0, NULL }
};
static int print_svcparam_no_value(struct buffer *output, uint16_t svcparamkey,
const uint8_t* data, uint16_t datalen);
static int print_svcparam_mandatory(struct buffer *output,
uint16_t svcparamkey, const uint8_t* data, uint16_t datalen);
static int print_svcparam_alpn(struct buffer *output,
uint16_t svcparamkey, const uint8_t* data, uint16_t datalen);
static int print_svcparam_port(struct buffer *output,
uint16_t svcparamkey, const uint8_t* data, uint16_t datalen);
static int print_svcparam_ipv4hint(struct buffer *output,
uint16_t svcparamkey, const uint8_t* data, uint16_t datalen);
static int print_svcparam_ech(struct buffer *output,
uint16_t svcparamkey, const uint8_t* data, uint16_t datalen);
static int print_svcparam_ipv6hint(struct buffer *output,
uint16_t svcparamkey, const uint8_t* data, uint16_t datalen);
static int print_svcparam_dohpath(struct buffer *output,
uint16_t svcparamkey, const uint8_t* data, uint16_t datalen);
static int print_svcparam_tls_supported_groups(struct buffer *output,
uint16_t svcparamkey, const uint8_t* data, uint16_t datalen);
static const nsd_svcparam_descriptor_type svcparams[] = {
{ SVCB_KEY_MANDATORY, "mandatory", print_svcparam_mandatory },
{ SVCB_KEY_ALPN, "alpn", print_svcparam_alpn },
{ SVCB_KEY_NO_DEFAULT_ALPN, "no-default-alpn",
print_svcparam_no_value },
{ SVCB_KEY_PORT, "port", print_svcparam_port },
{ SVCB_KEY_IPV4HINT, "ipv4hint", print_svcparam_ipv4hint },
{ SVCB_KEY_ECH, "ech", print_svcparam_ech },
{ SVCB_KEY_IPV6HINT, "ipv6hint", print_svcparam_ipv6hint },
{ SVCB_KEY_DOHPATH, "dohpath", print_svcparam_dohpath },
{ SVCB_KEY_OHTTP, "ohttp", print_svcparam_no_value },
{ SVCB_KEY_TLS_SUPPORTED_GROUPS, "tls-supported-groups",
print_svcparam_tls_supported_groups },
};
static int
print_name_literal(struct buffer *output, uint16_t rdlength,
const uint8_t *rdata, uint16_t *offset)
{
const uint8_t *name, *label, *limit;
assert(rdlength >= *offset);
if (rdlength < *offset || rdlength - *offset == 0)
return 0;
name = rdata + *offset;
label = name;
limit = rdata + rdlength;
if(*label) {
do {
if (label - name > MAXDOMAINLEN-1
|| *label > MAXLABELLEN
|| limit - label < 2 + *label)
return 0;
label += 1 + *label;
} while (*label);
} else {
}
buffer_printf(output, "%s", wiredname2str(name));
*offset += (label - name) + 1 ;
return 1;
}
static int
print_domain(struct buffer *output, uint16_t rdlength, const uint8_t *rdata,
uint16_t *offset)
{
const struct dname *dname;
struct domain *domain;
if(rdlength < *offset || rdlength - *offset < (uint16_t)sizeof(void*))
return 0;
memcpy(&domain, rdata+*offset, sizeof(void*));
dname = domain_dname(domain);
buffer_printf(output, "%s", dname_to_string(dname, NULL));
*offset += sizeof(void*);
return 1;
}
static inline int32_t
skip_string(struct buffer* output, uint16_t rdlength, uint16_t* offset)
{
int32_t length;
if (rdlength < *offset || rdlength - *offset < 1)
return -1;
length = buffer_read_u8(output);
if (length + 1 > rdlength - *offset)
return -1;
buffer_skip(output, length);
*offset += length + 1;
return length + 1;
}
static inline int32_t
skip_strings(struct buffer* output, uint16_t rdlength, uint16_t* offset)
{
int32_t olen = 0;
while(*offset < rdlength) {
int32_t slen = skip_string(output, rdlength, offset);
if(slen < 0)
return slen;
olen += slen;
}
return olen;
}
static int
print_string(struct buffer *output, uint16_t rdlength, const uint8_t *rdata,
uint16_t *offset)
{
size_t n;
if(rdlength - *offset < 1)
return 0;
n = rdata[*offset];
if(rdlength < *offset || (size_t)rdlength - *offset < 1 + n)
return 0;
buffer_printf(output, "\"");
for (size_t i = 1; i <= n; i++) {
char ch = (char) rdata[*offset+i];
if (isprint((unsigned char)ch)) {
if (ch == '"' || ch == '\\') {
buffer_printf(output, "\\");
}
buffer_printf(output, "%c", ch);
} else {
buffer_printf(output, "\\%03u",
(unsigned) rdata[*offset+i]);
}
}
buffer_printf(output, "\"");
*offset += 1;
*offset += n;
return 1;
}
static int32_t
print_text(struct buffer *output, uint16_t rdlength, const uint8_t *rdata,
uint16_t *offset)
{
buffer_printf(output, "\"");
for (size_t i = *offset; i < rdlength; ++i) {
char ch = (char) rdata[i];
if (isprint((unsigned char)ch)) {
if (ch == '"' || ch == '\\') {
buffer_printf(output, "\\");
}
buffer_printf(output, "%c", ch);
} else {
buffer_printf(output, "\\%03u", (unsigned) rdata[i]);
}
}
buffer_printf(output, "\"");
*offset = rdlength;
return 1;
}
static int
print_unquoted(buffer_type *output, uint16_t rdlength,
const uint8_t* rdata, uint16_t* offset)
{
uint8_t len;
size_t i;
if(rdlength < *offset || rdlength - *offset < 1)
return 0;
len = rdata[*offset];
if(((size_t)len) + 1 > (size_t)rdlength - *offset)
return 0;
for (i = 1; i <= (size_t)len; ++i) {
char ch = (char) rdata[*offset + i];
if (isprint((unsigned char)ch)) {
if (ch == '"' || ch == '\\' || ch == '(' || ch == ')'
|| ch == '\'' || isspace((unsigned char)ch)) {
buffer_printf(output, "\\");
}
buffer_printf(output, "%c", ch);
} else {
buffer_printf(output, "\\%03u",
(unsigned) rdata[*offset + i]);
}
}
*offset += 1;
*offset += len;
return 1;
}
static int
print_unquoteds(buffer_type *output, uint16_t rdlength,
const uint8_t* rdata, uint16_t* offset)
{
while (*offset < rdlength) {
if(!print_unquoted(output, rdlength, rdata, offset))
return 0;
if(*offset < rdlength)
buffer_printf(output, " ");
}
return 1;
}
static int
print_ip4(struct buffer *output, size_t rdlength, const uint8_t *rdata,
uint16_t *offset)
{
char str[INET_ADDRSTRLEN + 1];
if(((size_t)*offset) + 4 > rdlength)
return 0;
if(!inet_ntop(AF_INET, rdata + *offset, str, sizeof(str)))
return 0;
buffer_printf(output, "%s", str);
*offset += 4;
return 1;
}
static int
print_ip6(struct buffer *output, size_t rdlength, const uint8_t *rdata,
uint16_t *offset)
{
char str[INET6_ADDRSTRLEN + 1];
if (rdlength < *offset || rdlength - *offset < 16)
return 0;
if (!inet_ntop(AF_INET6, rdata + *offset, str, sizeof(str)))
return 0;
buffer_printf(output, "%s", str);
*offset += 16;
return 1;
}
static int
print_ilnp64(struct buffer *output, uint16_t rdlength, const uint8_t *rdata,
uint16_t *offset)
{
uint16_t a1, a2, a3, a4;
if (rdlength < *offset || rdlength - *offset < 8)
return 0;
a1 = read_uint16(rdata + *offset);
a2 = read_uint16(rdata + *offset + 2);
a3 = read_uint16(rdata + *offset + 4);
a4 = read_uint16(rdata + *offset + 6);
buffer_printf(output, "%.4x:%.4x:%.4x:%.4x", a1, a2, a3, a4);
*offset += 8;
return 1;
}
static int
print_certificate_type(struct buffer *output, size_t rdlength,
const uint8_t *rdata, uint16_t *offset)
{
uint16_t id;
lookup_table_type* type;
if (rdlength < *offset || rdlength - *offset < 2)
return 0;
id = read_uint16(rdata + *offset);
type = lookup_by_id(dns_certificate_types, id);
if (type)
buffer_printf(output, "%s", type->name);
else
buffer_printf(output, "%u", (unsigned) id);
*offset += 2;
return 1;
}
static int
print_time(struct buffer *output, uint16_t rdlength, const uint8_t *rdata,
uint16_t *offset)
{
time_t time;
struct tm tmbuf;
struct tm* tm;
char buf[15];
if (rdlength < *offset || rdlength - *offset < 4)
return 0;
time = (time_t)read_uint32(rdata + *offset);
tm = gmtime_r(&time, &tmbuf);
if (!strftime(buf, sizeof(buf), "%Y%m%d%H%M%S", tm))
return 0;
buffer_printf(output, "%s", buf);
*offset += 4;
return 1;
}
static int
print_base32(struct buffer *output, uint16_t rdlength, const uint8_t *rdata,
uint16_t *offset)
{
size_t size;
int length;
if(rdlength < *offset || rdlength - *offset == 0)
return 0;
size = rdata[*offset];
if (rdlength - ((size_t)*offset) < 1 + size)
return 0;
if (size == 0) {
buffer_write(output, "-", 1);
*offset += 1;
return 1;
}
buffer_reserve(output, size * 2 + 1);
length = b32_ntop(rdata + *offset + 1, size,
(char *)buffer_current(output), size * 2);
if (length == -1)
return 0;
buffer_skip(output, length);
*offset += 1 + size;
return 1;
}
static int
print_base64(struct buffer *output, uint16_t rdlength, const uint8_t *rdata,
uint16_t *offset)
{
int length;
size_t size = rdlength - *offset;
if(rdlength < *offset)
return 0;
if(size == 0) {
buffer_write(output, "0", 1);
return 1;
}
buffer_reserve(output, size * 2 + 1);
length = __b64_ntop(rdata + *offset, size,
(char *) buffer_current(output), size * 2);
if (length == -1)
return 0;
buffer_skip(output, length);
*offset += size;
return 1;
}
static void
buffer_print_hex(buffer_type *output, const uint8_t *data, size_t size)
{
static const char hexdigits[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
size_t i;
buffer_reserve(output, size * 2);
for (i = 0; i < size; ++i) {
uint8_t octet = *data++;
buffer_write_u8(output, hexdigits[octet >> 4]);
buffer_write_u8(output, hexdigits[octet & 0x0f]);
}
}
static int
print_base16(struct buffer *output, uint16_t rdlength, const uint8_t *rdata,
uint16_t *offset)
{
size_t size = rdlength - *offset;
if(rdlength < *offset)
return 0;
if(size == 0) {
buffer_write(output, "0", 1);
return 1;
} else {
buffer_print_hex(output, rdata+*offset, size);
}
*offset += size;
return 1;
}
static int
print_salt(struct buffer *output, uint16_t rdlength, const uint8_t *rdata,
uint16_t *offset)
{
uint8_t length;
if (rdlength < *offset || rdlength - *offset == 0)
return 0;
length = rdata[*offset];
if (rdlength - *offset < 1 + length)
return 0;
if (!length)
buffer_printf(output, "-");
else
buffer_print_hex(output, rdata + *offset + 1, length);
*offset += 1 + (uint16_t)length;
return 1;
}
static inline int32_t
skip_nsec(struct buffer* packet, uint16_t rdlength, uint16_t *offset)
{
uint16_t length = 0;
uint8_t last_window = 0;
while (rdlength - *offset - length > 2) {
uint8_t window = buffer_read_u8(packet);
uint8_t blocks = buffer_read_u8(packet);
if (length > 0 && window <= last_window)
return -1;
if (!blocks || blocks > 32)
return -1;
if (rdlength - *offset - length < 2 + blocks)
return -1;
buffer_skip(packet, blocks);
length += 2 + blocks;
last_window = window;
}
*offset += length;
if (rdlength != *offset)
return -1;
return length;
}
static int
print_nsec_bitmap(struct buffer *output, uint16_t rdlength,
const uint8_t *rdata, uint16_t *offset)
{
int insert_space = 0;
if(rdlength < *offset)
return 0;
rdata += *offset;
while(rdlength - *offset > 0) {
uint8_t window, bitmap_size;
const uint8_t* bitmap;
int i;
if(rdlength - *offset < 2)
return 0;
window = rdata[0];
bitmap_size = rdata[1];
*offset += 2;
if(rdlength - *offset < bitmap_size)
return 0;
bitmap = rdata + 2;
rdata += 2;
for(i=0; i<((int)bitmap_size)*8; i++) {
if (get_bit(bitmap, i)) {
buffer_printf(output,
"%s%s",
insert_space ? " " : "",
rrtype_to_string(
window * 256 + i));
insert_space = 1;
}
}
rdata += bitmap_size;
*offset += bitmap_size;
}
return 1;
}
static int
svcparam_must_have_value(uint16_t svcparamkey)
{
switch (svcparamkey) {
case SVCB_KEY_ALPN:
case SVCB_KEY_PORT:
case SVCB_KEY_IPV4HINT:
case SVCB_KEY_IPV6HINT:
case SVCB_KEY_MANDATORY:
case SVCB_KEY_DOHPATH:
case SVCB_KEY_TLS_SUPPORTED_GROUPS:
return 1;
default:
break;
}
return 0;
}
static int
svcparam_must_not_have_value(uint16_t svcparamkey)
{
switch (svcparamkey) {
case SVCB_KEY_NO_DEFAULT_ALPN:
case SVCB_KEY_OHTTP:
return 1;
default:
break;
}
return 0;
}
static inline int
skip_svcparams(struct buffer *packet, uint16_t rdlength)
{
unsigned pos = 0;
uint16_t key, count;
while(pos < rdlength) {
if(pos+4 > (unsigned)rdlength)
return 0;
if(!buffer_available(packet, 4))
return 0;
key = buffer_read_u16(packet);
count = buffer_read_u16(packet);
if(count == 0 && svcparam_must_have_value(key))
return 0;
if(count != 0 && svcparam_must_not_have_value(key))
return 0;
pos += 4;
if(pos+count > (unsigned)rdlength)
return 0;
if(!buffer_available(packet, count))
return 0;
buffer_skip(packet, count);
pos += count;
}
return 1;
}
static void
buffer_print_svcparamkey(buffer_type *output, uint16_t svcparamkey)
{
if (svcparamkey < sizeof(svcparams)/sizeof(svcparams[0]))
buffer_printf(output, "%s", svcparams[svcparamkey].name);
else
buffer_printf(output, "key%" PRIu16, svcparamkey);
}
static int
print_svcparam_no_value(struct buffer *output, uint16_t svcparamkey,
const uint8_t* ATTR_UNUSED(data), uint16_t ATTR_UNUSED(datalen))
{
buffer_print_svcparamkey(output, svcparamkey);
return 1;
}
static int
print_svcparam_mandatory(struct buffer *output, uint16_t svcparamkey,
const uint8_t* data, uint16_t datalen)
{
assert(datalen > 0);
if (datalen % sizeof(uint16_t))
return 0;
buffer_print_svcparamkey(output, svcparamkey);
buffer_write_u8(output, '=');
buffer_print_svcparamkey(output, read_uint16(data));
data += 2;
while ((datalen -= sizeof(uint16_t))) {
buffer_write_u8(output, ',');
buffer_print_svcparamkey(output, read_uint16(data));
data += 2;
}
return 1;
}
static int
print_svcparam_alpn(struct buffer *output, uint16_t svcparamkey,
const uint8_t* data, uint16_t datalen)
{
uint8_t *dp = (void *)data;
assert(datalen > 0);
buffer_print_svcparamkey(output, svcparamkey);
buffer_write_u8(output, '=');
buffer_write_u8(output, '"');
while (datalen) {
uint8_t i, str_len = *dp++;
if (str_len > --datalen)
return 0;
for (i = 0; i < str_len; i++) {
if (dp[i] == '"' || dp[i] == '\\')
buffer_printf(output, "\\\\\\%c", dp[i]);
else if (dp[i] == ',')
buffer_printf(output, "\\\\%c", dp[i]);
else if (!isprint(dp[i]))
buffer_printf(output, "\\%03u", (unsigned) dp[i]);
else
buffer_write_u8(output, dp[i]);
}
dp += str_len;
if ((datalen -= str_len))
buffer_write_u8(output, ',');
}
buffer_write_u8(output, '"');
return 1;
}
static int
print_svcparam_port(struct buffer *output, uint16_t svcparamkey,
const uint8_t* data, uint16_t datalen)
{
if (datalen != 2)
return 0;
buffer_print_svcparamkey(output, svcparamkey);
buffer_printf(output, "=%d", (int)read_uint16(data));
return 1;
}
static int
print_svcparam_ipv4hint(struct buffer *output, uint16_t svcparamkey,
const uint8_t* data, uint16_t datalen)
{
char ip_str[INET_ADDRSTRLEN + 1];
assert(datalen > 0);
buffer_print_svcparamkey(output, svcparamkey);
if ((datalen % IP4ADDRLEN) == 0) {
if (inet_ntop(AF_INET, data, ip_str, sizeof(ip_str)) == NULL)
return 0;
buffer_printf(output, "=%s", ip_str);
data += IP4ADDRLEN;
while ((datalen -= IP4ADDRLEN) > 0) {
if (inet_ntop(AF_INET, data, ip_str, sizeof(ip_str))
== NULL)
return 0;
buffer_printf(output, ",%s", ip_str);
data += IP4ADDRLEN;
}
return 1;
}
return 0;
}
static int
print_svcparam_ech(struct buffer *output, uint16_t svcparamkey,
const uint8_t* data, uint16_t datalen)
{
int length;
buffer_print_svcparamkey(output, svcparamkey);
if(datalen == 0)
return 1;
buffer_write_u8(output, '=');
buffer_reserve(output, datalen * 2 + 1);
length = __b64_ntop(data, datalen, (char*)buffer_current(output),
datalen * 2);
if (length > 0) {
buffer_skip(output, length);
}
return length != -1;
}
static int
print_svcparam_ipv6hint(struct buffer *output, uint16_t svcparamkey,
const uint8_t* data, uint16_t datalen)
{
char ip_str[INET6_ADDRSTRLEN + 1];
assert(datalen > 0);
buffer_print_svcparamkey(output, svcparamkey);
if ((datalen % IP6ADDRLEN) == 0) {
if (inet_ntop(AF_INET6, data, ip_str, sizeof(ip_str)) == NULL)
return 0;
buffer_printf(output, "=%s", ip_str);
data += IP6ADDRLEN;
while ((datalen -= IP6ADDRLEN) > 0) {
if (inet_ntop(AF_INET6, data, ip_str, sizeof(ip_str))
== NULL)
return 0;
buffer_printf(output, ",%s", ip_str);
data += IP6ADDRLEN;
}
return 1;
}
return 0;
}
static int
print_svcparam_dohpath(struct buffer *output, uint16_t svcparamkey,
const uint8_t* data, uint16_t datalen)
{
const uint8_t* dp = data;
unsigned i;
buffer_print_svcparamkey(output, svcparamkey);
buffer_write(output, "=\"", 2);
for (i = 0; i < datalen; i++) {
if (dp[i] == '"' || dp[i] == '\\')
buffer_printf(output, "\\%c", dp[i]);
else if (!isprint(dp[i]))
buffer_printf(output, "\\%03u", (unsigned) dp[i]);
else
buffer_write_u8(output, dp[i]);
}
buffer_write_u8(output, '"');
return 1;
}
static int
print_svcparam_tls_supported_groups(struct buffer *output,
uint16_t svcparamkey, const uint8_t* data, uint16_t datalen)
{
assert(datalen > 0);
if ((datalen % sizeof(uint16_t)) == 1)
return 0;
buffer_print_svcparamkey(output, svcparamkey);
buffer_printf(output, "=%d", (int)read_uint16(data));
data += 2;
while ((datalen -= sizeof(uint16_t)) > 0) {
buffer_printf(output, ",%d", (int)read_uint16(data));
data += 2;
}
return 1;
}
static int
print_svcparam(struct buffer *output, uint16_t rdlength, const uint8_t *rdata,
uint16_t *offset)
{
uint16_t key, length;
const uint8_t* dp;
unsigned i;
if (rdlength < *offset || rdlength - *offset < 4)
return 0;
key = read_uint16(rdata + *offset);
length = read_uint16(rdata + *offset + 2);
if (rdlength - *offset < length + 4)
return 0;
if(length == 0 && svcparam_must_have_value(key))
return 0;
if(length != 0 && svcparam_must_not_have_value(key))
return 0;
if (key < sizeof(svcparams)/sizeof(svcparams[0])) {
if(!svcparams[key].print_rdata(output, key, rdata+*offset+4, length))
return 0;
*offset += length+4;
return 1;
}
buffer_printf(output, "key%" PRIu16, key);
if (!length) {
*offset += 4;
return 1;
}
buffer_write(output, "=\"", 2);
dp = rdata + *offset + 4;
for (i = 0; i < length; i++) {
if (dp[i] == '"' || dp[i] == '\\')
buffer_printf(output, "\\%c", dp[i]);
else if (!isprint(dp[i]))
buffer_printf(output, "\\%03u", (unsigned) dp[i]);
else
buffer_write_u8(output, dp[i]);
}
buffer_write_u8(output, '"');
*offset += length + 4;
return 1;
}
static inline int32_t
read_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
if (buffer_remaining(packet) < rdlength)
return MALFORMED;
if (!(*rr = region_alloc(domains->region, sizeof(**rr) + rdlength)))
return TRUNCATED;
if(rdlength != 0)
buffer_read(packet, (*rr)->rdata, rdlength);
(*rr)->rdlength = rdlength;
return rdlength;
}
int32_t
read_generic_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
return read_rdata(domains, rdlength, packet, rr);
}
void
write_generic_rdata(struct query *query, const struct rr *rr)
{
if(rr->rdlength != 0)
buffer_write(query->packet, rr->rdata, rr->rdlength);
}
int
print_generic_rdata(struct buffer *output, const struct rr *rr)
{
const nsd_type_descriptor_type* descriptor =
nsd_type_descriptor(rr->type);
return print_unknown_rdata_field(output, descriptor, rr);
}
int
lookup_rdata_field_entry(const nsd_type_descriptor_type* descriptor,
size_t index, const rr_type* rr, uint16_t offset, uint16_t* field_len,
struct domain** domain)
{
const nsd_rdata_descriptor_type* field =
&descriptor->rdata.fields[index];
if(field->calculate_length) {
int32_t l = field->calculate_length(rr->rdlength, rr->rdata,
offset, domain);
if(l < 0)
return 0;
*field_len = l;
} else if(field->length >= 0) {
*field_len = field->length;
*domain = NULL;
} else {
size_t dlen;
int32_t flen;
if(offset > rr->rdlength)
return 0;
switch(field->length) {
case RDATA_COMPRESSED_DNAME:
case RDATA_UNCOMPRESSED_DNAME:
if(rr->rdlength - offset <
(uint16_t)sizeof(void*))
return 0;
*field_len = sizeof(void*);
memcpy(domain, rr->rdata+offset, sizeof(void*));
break;
case RDATA_LITERAL_DNAME:
dlen = buf_dname_length(rr->rdata+offset,
rr->rdlength-offset);
if(dlen == 0)
return 0;
*field_len = dlen;
*domain = NULL;
break;
case RDATA_STRING:
case RDATA_BINARY:
if(rr->rdlength - offset < 1)
return 0;
flen = (rr->rdata+offset)[0];
*field_len = flen+1;
*domain = NULL;
break;
case RDATA_IPSECGATEWAY:
case RDATA_AMTRELAY_RELAY:
return 0;
case RDATA_REMAINDER:
*field_len = rr->rdlength - offset;
*domain = NULL;
break;
default:
return 0;
}
}
if(offset + *field_len > rr->rdlength)
return 0;
return 1;
}
int
lookup_rdata_field_entry_uncompressed_wire(
const nsd_type_descriptor_type* descriptor, size_t index,
const uint8_t* rdata, uint16_t rdlength, uint16_t offset,
uint16_t* field_len, struct domain** domain)
{
const nsd_rdata_descriptor_type* field =
&descriptor->rdata.fields[index];
if(field->calculate_length) {
int32_t l = field->calculate_length_uncompressed_wire(rdlength,
rdata, offset, domain);
if(l < 0)
return 0;
*field_len = l;
} else if(field->length >= 0) {
*field_len = field->length;
*domain = NULL;
} else {
size_t dlen;
int32_t flen;
if(offset > rdlength)
return 0;
switch(field->length) {
case RDATA_COMPRESSED_DNAME:
case RDATA_UNCOMPRESSED_DNAME:
case RDATA_LITERAL_DNAME:
dlen = buf_dname_length(rdata+offset, rdlength-offset);
if(dlen == 0)
return 0;
*field_len = dlen;
*domain = NULL;
break;
case RDATA_STRING:
case RDATA_BINARY:
if(rdlength - offset < 1)
return 0;
flen = (rdata+offset)[0];
*field_len = flen+1;
*domain = NULL;
break;
case RDATA_IPSECGATEWAY:
case RDATA_AMTRELAY_RELAY:
return 0;
case RDATA_REMAINDER:
*field_len = rdlength - offset;
*domain = NULL;
break;
default:
return 0;
}
}
if(offset + *field_len > rdlength)
return 0;
return 1;
}
int32_t
rr_calculate_uncompressed_rdata_length(const rr_type* rr)
{
size_t i;
const nsd_type_descriptor_type* descriptor =
nsd_type_descriptor(rr->type);
uint16_t offset = 0;
int32_t result = 0;
if(!descriptor->has_references)
return rr->rdlength;
for(i=0; i < descriptor->rdata.length; i++) {
uint16_t field_len;
struct domain* domain;
if(rr->rdlength == offset &&
descriptor->rdata.fields[i].is_optional)
break;
if(!lookup_rdata_field_entry(descriptor, i, rr, offset,
&field_len, &domain))
return -1;
if(domain != NULL) {
const struct dname* dname = domain_dname(domain);
result += dname->name_size;
} else {
result += field_len;
}
offset += field_len;
}
return result;
}
void
rr_write_uncompressed_rdata(const rr_type* rr, uint8_t* buf, size_t len)
{
size_t i;
const nsd_type_descriptor_type* descriptor =
nsd_type_descriptor(rr->type);
uint16_t offset = 0;
size_t pos = 0;
if(!descriptor->has_references) {
if(rr->rdlength > len)
return;
memcpy(buf, rr->rdata, rr->rdlength);
return;
}
for(i=0; i < descriptor->rdata.length; i++) {
uint16_t field_len;
struct domain* domain;
if(rr->rdlength == offset &&
descriptor->rdata.fields[i].is_optional)
break;
if(!lookup_rdata_field_entry(descriptor, i, rr, offset,
&field_len, &domain))
return;
if(domain != NULL) {
const struct dname* dname = domain_dname(domain);
if(pos + dname->name_size > len)
return;
memcpy(buf+pos, dname_name(dname), dname->name_size);
pos += dname->name_size;
} else {
if(pos + field_len > len)
return;
memcpy(buf+pos, rr->rdata+offset, field_len);
pos += field_len;
}
offset += field_len;
}
}
int print_unknown_rdata_field(buffer_type *output,
const nsd_type_descriptor_type *descriptor, const rr_type *rr)
{
size_t i;
int32_t size;
uint16_t length = 0;
if(!descriptor->has_references) {
buffer_printf(output, "\\# %lu ", (unsigned long)rr->rdlength);
buffer_print_hex(output, rr->rdata, rr->rdlength);
return 1;
}
size = rr_calculate_uncompressed_rdata_length(rr);
if(size < 0)
return 0;
buffer_printf(output, "\\# %lu ", (unsigned long) size);
for(i=0; i < descriptor->rdata.length; i++) {
uint16_t field_len;
struct domain* domain;
const uint8_t* to_print;
size_t to_print_len;
if(rr->rdlength == length &&
descriptor->rdata.fields[i].is_optional)
break;
if(!lookup_rdata_field_entry(descriptor, i, rr, length,
&field_len, &domain))
return 0;
if(domain != NULL) {
const struct dname* dname = domain_dname(domain);
to_print = dname_name(dname);
to_print_len = dname->name_size;
} else {
to_print = rr->rdata+length;
to_print_len = field_len;
}
buffer_print_hex(output, to_print, to_print_len);
length += field_len;
}
return 1;
}
int print_unknown_rdata(buffer_type *output,
const nsd_type_descriptor_type *descriptor, const rr_type *rr)
{
buffer_printf(output, "\t");
return print_unknown_rdata_field(output, descriptor, rr);
}
int32_t
read_compressed_name_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
struct domain *domain;
struct dname_buffer dname;
size_t size;
const size_t mark = buffer_position(packet);
if (!dname_make_from_packet_buffered(&dname, packet, 1, 1) ||
rdlength != buffer_position(packet) - mark)
return MALFORMED;
size = sizeof(**rr) + sizeof(void*);
if (!(*rr = region_alloc(domains->region, size)))
return TRUNCATED;
domain = domain_table_insert(domains, (void*)&dname);
domain->usage++;
memcpy((*rr)->rdata, &domain, sizeof(void*));
(*rr)->rdlength = sizeof(void*);
return rdlength;
}
int32_t
read_uncompressed_name_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
struct domain *domain;
struct dname_buffer dname;
size_t size;
const size_t mark = buffer_position(packet);
if (!dname_make_from_packet_buffered(&dname, packet,
1 , 1) ||
rdlength != buffer_position(packet)-mark)
return MALFORMED;
size = sizeof(**rr) + sizeof(void*);
if (!(*rr = region_alloc(domains->region, size)))
return TRUNCATED;
domain = domain_table_insert(domains, (void*)&dname);
domain->usage++;
memcpy((*rr)->rdata, &domain, sizeof(void*));
(*rr)->rdlength = sizeof(void*);
return rdlength;
}
static void
encode_dname(query_type *q, domain_type *domain)
{
while (domain->parent && query_get_dname_offset(q, domain) == 0) {
query_put_dname_offset(q, domain, buffer_position(q->packet));
DEBUG(DEBUG_NAME_COMPRESSION, 2,
(LOG_INFO, "dname: %s, number: %lu, offset: %u\n",
domain_to_string(domain),
(unsigned long) domain->number,
query_get_dname_offset(q, domain)));
buffer_write(q->packet, dname_name(domain_dname(domain)),
label_length(dname_name(domain_dname(domain))) + 1U);
domain = domain->parent;
}
if (domain->parent) {
DEBUG(DEBUG_NAME_COMPRESSION, 2,
(LOG_INFO, "dname: %s, number: %lu, pointer: %u\n",
domain_to_string(domain),
(unsigned long) domain->number,
query_get_dname_offset(q, domain)));
assert(query_get_dname_offset(q, domain) <= MAX_COMPRESSION_OFFSET);
buffer_write_u16(q->packet,
0xc000 | query_get_dname_offset(q, domain));
} else {
buffer_write_u8(q->packet, 0);
}
}
void
write_compressed_name_rdata(struct query *query, const struct rr *rr)
{
struct domain *domain;
assert(rr->rdlength == sizeof(void*));
memcpy(&domain, rr->rdata, sizeof(void*));
encode_dname(query, domain);
}
void
write_uncompressed_name_rdata(struct query *query, const struct rr *rr)
{
const struct dname *dname;
struct domain *domain;
assert(rr->rdlength >= sizeof(void*));
memcpy(&domain, rr->rdata, sizeof(void*));
dname = domain_dname(domain);
buffer_write(query->packet, dname_name(dname), dname->name_size);
}
int
print_name_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
assert(rr->rdlength == sizeof(void*));
return print_domain(output, rr->rdlength, rr->rdata, &length);
}
int32_t
read_a_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
if (rdlength != 4)
return MALFORMED;
return read_rdata(domains, rdlength, packet, rr);
}
int
print_a_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
assert(rr->rdlength == 4);
return print_ip4(output, rr->rdlength, rr->rdata, &length);
}
int32_t
read_soa_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
struct domain *primary_domain, *mailbox_domain;
struct dname_buffer primary, mailbox;
size_t size;
const size_t mark = buffer_position(packet);
if (!dname_make_from_packet_buffered(&primary, packet, 1, 1) ||
!dname_make_from_packet_buffered(&mailbox, packet, 1, 1) ||
rdlength != (buffer_position(packet) - mark) + 20)
return MALFORMED;
size = sizeof(**rr) + 2 * sizeof(void*) + 20;
if (!(*rr = region_alloc(domains->region, size)))
return TRUNCATED;
primary_domain = domain_table_insert(domains, (void*)&primary);
primary_domain->usage++;
mailbox_domain = domain_table_insert(domains, (void*)&mailbox);
mailbox_domain->usage++;
memcpy((*rr)->rdata, &primary_domain, sizeof(void*));
memcpy((*rr)->rdata + sizeof(void*), &mailbox_domain, sizeof(void*));
buffer_read(packet, (*rr)->rdata + 2 * sizeof(void*), 20);
(*rr)->rdlength = 2 * sizeof(void*) + 20;
return rdlength;
}
void
write_soa_rdata(struct query *query, const struct rr *rr)
{
struct domain *primary, *mailbox;
assert(rr->rdlength == 2 * sizeof(void*) + 20);
memcpy(&primary, rr->rdata, sizeof(void*));
memcpy(&mailbox, rr->rdata + sizeof(void*), sizeof(void*));
encode_dname(query, primary);
encode_dname(query, mailbox);
buffer_write(query->packet, rr->rdata + (2 * sizeof(void*)), 20);
}
int
print_soa_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
uint32_t serial, refresh, retry, expire, minimum;
assert(rr->rdlength == 2 * sizeof(void*) + 20);
if (!print_domain(output, rr->rdlength, rr->rdata, &length))
return 0;
buffer_printf(output, " ");
if (!print_domain(output, rr->rdlength, rr->rdata, &length))
return 0;
assert(length == 2 * sizeof(void*));
serial = read_uint32(rr->rdata + length);
refresh = read_uint32(rr->rdata + length + 4);
retry = read_uint32(rr->rdata + length + 8);
expire = read_uint32(rr->rdata + length + 12);
minimum = read_uint32(rr->rdata + length + 16);
buffer_printf(
output, " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32,
serial, refresh, retry, expire, minimum);
return 1;
}
int
print_soa_rdata_twoline(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
uint32_t serial, refresh, retry, expire, minimum;
assert(rr->rdlength == 2 * sizeof(void*) + 20);
if (!print_domain(output, rr->rdlength, rr->rdata, &length))
return 0;
buffer_printf(output, " ");
if (!print_domain(output, rr->rdlength, rr->rdata, &length))
return 0;
assert(length == 2 * sizeof(void*));
serial = read_uint32(rr->rdata + length);
refresh = read_uint32(rr->rdata + length + 4);
retry = read_uint32(rr->rdata + length + 8);
expire = read_uint32(rr->rdata + length + 12);
minimum = read_uint32(rr->rdata + length + 16);
buffer_printf(
output, " (\n\t\t%" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " )",
serial, refresh, retry, expire, minimum);
return 1;
}
int32_t
read_wks_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
if (rdlength < 5)
return MALFORMED;
return read_rdata(domains, rdlength, packet, rr);
}
int
print_wks_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
uint8_t protocol;
int bits;
const uint8_t* bitmap;
if(rr->rdlength < 5)
return 0;
if (!print_ip4(output, rr->rdlength, rr->rdata, &length))
return 0;
buffer_printf(output, " ");
protocol = rr->rdata[4];
if(protocol == 6)
buffer_printf(output, "tcp");
else if(protocol == 17)
buffer_printf(output, "udp");
else
buffer_printf(output, "%" PRIu8, protocol);
bits = (rr->rdlength - 5) * 8;
bitmap = rr->rdata + 5;
for (int service = 0; service < bits; service++) {
if (get_bit(bitmap, service))
buffer_printf(output, " %d", service);
}
return 1;
}
int32_t
read_hinfo_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
uint16_t length = 0;
const size_t mark = buffer_position(packet);
if(!buffer_available(packet, rdlength))
return MALFORMED;
if (skip_string(packet, rdlength, &length) < 0
|| skip_string(packet, rdlength, &length) < 0
|| rdlength != length)
return MALFORMED;
buffer_set_position(packet, mark);
return read_rdata(domains, rdlength, packet, rr);
}
int
print_hinfo_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
if (!print_string(output, rr->rdlength, rr->rdata, &length))
return 0;
buffer_printf(output, " ");
if (!print_string(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_minfo_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
struct domain *rmailbx_domain, *emailbx_domain;
struct dname_buffer rmailbx, emailbx;
size_t size;
const size_t mark = buffer_position(packet);
if (buffer_remaining(packet) < rdlength ||
!dname_make_from_packet_buffered(&rmailbx, packet, 1, 1) ||
!dname_make_from_packet_buffered(&emailbx, packet, 1, 1) ||
rdlength != buffer_position(packet)-mark)
return MALFORMED;
size = sizeof(**rr) + 2 * sizeof(void*);
if (!(*rr = region_alloc(domains->region, size)))
return TRUNCATED;
rmailbx_domain = domain_table_insert(domains, (void*)&rmailbx);
rmailbx_domain->usage++;
emailbx_domain = domain_table_insert(domains, (void*)&emailbx);
emailbx_domain->usage++;
memcpy((*rr)->rdata, &rmailbx_domain, sizeof(void*));
memcpy((*rr)->rdata + sizeof(void*), &emailbx_domain, sizeof(void*));
(*rr)->rdlength = 2 * sizeof(void*);
return rdlength;
}
void
write_minfo_rdata(struct query *query, const struct rr *rr)
{
struct domain *rmailbx, *emailbx;
assert(rr->rdlength == 2 * sizeof(void*));
memcpy(&rmailbx, rr->rdata, sizeof(void*));
memcpy(&emailbx, rr->rdata + sizeof(void*), sizeof(void*));
encode_dname(query, rmailbx);
encode_dname(query, emailbx);
}
int
print_minfo_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
assert(rr->rdlength == 2 * sizeof(void*));
if (!print_domain(output, rr->rdlength, rr->rdata, &length))
return 0;
buffer_printf(output, " ");
if (!print_domain(output, rr->rdlength, rr->rdata, &length))
return 0;
assert(rr->rdlength == length);
return 1;
}
int32_t
read_mx_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
struct domain *domain;
struct dname_buffer exchange;
size_t size;
const size_t mark = buffer_position(packet);
if (buffer_remaining(packet) < rdlength || rdlength < 2)
return MALFORMED;
buffer_skip(packet, 2);
if (!dname_make_from_packet_buffered(&exchange, packet, 1, 1))
return MALFORMED;
if (rdlength != buffer_position(packet)-mark)
return MALFORMED;
size = sizeof(**rr) + 2 + sizeof(void*);
if (!(*rr = region_alloc(domains->region, size)))
return -1;
domain = domain_table_insert(domains, (void*)&exchange);
domain->usage++;
buffer_read_at(packet, mark, (*rr)->rdata, 2);
memcpy((*rr)->rdata + 2, &domain, sizeof(void*));
(*rr)->rdlength = 2 + sizeof(void*);
return rdlength;
}
void
write_mx_rdata(struct query *query, const struct rr *rr)
{
struct domain *domain;
assert(rr->rdlength == 2 + sizeof(void*));
memcpy(&domain, rr->rdata + 2, sizeof(void*));
buffer_write(query->packet, rr->rdata, 2);
encode_dname(query, domain);
}
int
print_mx_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 2;
assert(rr->rdlength > length);
buffer_printf(output, "%" PRIu16 " ", read_uint16(rr->rdata));
if (!print_domain(output, rr->rdlength, rr->rdata, &length))
return 0;
assert(rr->rdlength == length);
return 1;
}
int32_t
read_txt_rdata(struct domain_table *owners, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
uint16_t length = 0;
const size_t mark = buffer_position(packet);
if(!buffer_available(packet, rdlength))
return MALFORMED;
if (skip_strings(packet, rdlength, &length) < 0 || rdlength != length)
return MALFORMED;
buffer_set_position(packet, mark);
return read_rdata(owners, rdlength, packet, rr);
}
int
print_txt_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
if (length < rr->rdlength) {
if (!print_string(output, rr->rdlength, rr->rdata, &length))
return 0;
while (length < rr->rdlength) {
buffer_printf(output, " ");
if (!print_string(output, rr->rdlength, rr->rdata,
&length))
return 0;
}
}
return 1;
}
int32_t
read_rp_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
struct domain *mbox_domain, *txt_domain;
struct dname_buffer mbox, txt;
size_t size;
const size_t mark = buffer_position(packet);
if (buffer_remaining(packet) < rdlength ||
!dname_make_from_packet_buffered(&mbox, packet, 1 , 1) ||
!dname_make_from_packet_buffered(&txt, packet, 1 , 1) ||
rdlength != buffer_position(packet)-mark)
return MALFORMED;
size = sizeof(**rr) + 2 * sizeof(void*);
if (!(*rr = region_alloc(domains->region, size)))
return TRUNCATED;
mbox_domain = domain_table_insert(domains, (void*)&mbox);
mbox_domain->usage++;
txt_domain = domain_table_insert(domains, (void*)&txt);
txt_domain->usage++;
memcpy((*rr)->rdata, &mbox_domain, sizeof(void*));
memcpy((*rr)->rdata + sizeof(void*), &txt_domain, sizeof(void*));
(*rr)->rdlength = 2 * sizeof(void*);
return rdlength;
}
void
write_rp_rdata(struct query *query, const struct rr *rr)
{
struct domain *mbox_domain, *txt_domain;
const struct dname *mbox, *txt;
assert(rr->rdlength == 2 * sizeof(void*));
memcpy(&mbox_domain, rr->rdata, sizeof(void*));
memcpy(&txt_domain, rr->rdata + sizeof(void*), sizeof(void*));
mbox = domain_dname(mbox_domain);
txt = domain_dname(txt_domain);
buffer_write(query->packet, dname_name(mbox), mbox->name_size);
buffer_write(query->packet, dname_name(txt), txt->name_size);
}
int
print_rp_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
if(!print_domain(output, rr->rdlength, rr->rdata, &length))
return 0;
buffer_printf(output, " ");
if(!print_domain(output, rr->rdlength, rr->rdata, &length))
return 0;
assert(rr->rdlength == length);
return 1;
}
int32_t
read_afsdb_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
struct domain *domain;
struct dname_buffer hostname;
size_t size;
const size_t mark = buffer_position(packet);
if (buffer_remaining(packet) < rdlength || rdlength < 2)
return MALFORMED;
buffer_skip(packet, 2);
if (!dname_make_from_packet_buffered(&hostname, packet,
1 , 1) ||
rdlength != buffer_position(packet)-mark)
return MALFORMED;
size = sizeof(**rr) + 2 + sizeof(void*);
if (!(*rr = region_alloc(domains->region, size)))
return TRUNCATED;
domain = domain_table_insert(domains, (void*)&hostname);
domain->usage++;
buffer_read_at(packet, mark, (*rr)->rdata, 2);
memcpy((*rr)->rdata + 2, &domain, sizeof(void*));
(*rr)->rdlength = 2 + sizeof(void*);
return rdlength;
}
void
write_afsdb_rdata(struct query *query, const struct rr *rr)
{
struct domain *domain;
const struct dname *dname;
assert(rr->rdlength == 2 + sizeof(void*));
memcpy(&domain, rr->rdata + 2, sizeof(void*));
dname = domain_dname(domain);
buffer_write(query->packet, rr->rdata, 2);
buffer_write(query->packet, dname_name(dname), dname->name_size);
}
int
print_afsdb_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t subtype, length=2;
assert(rr->rdlength == 2 + sizeof(void*));
subtype = read_uint16(rr->rdata);
buffer_printf(output, "%" PRIu16 " ", subtype);
if(!print_domain(output, rr->rdlength, rr->rdata, &length))
return 0;
return 1;
}
int32_t
read_x25_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
uint16_t length = 0;
const size_t mark = buffer_position(packet);
if(!buffer_available(packet, rdlength))
return MALFORMED;
if (skip_string(packet, rdlength, &length) < 0 || rdlength != length)
return MALFORMED;
buffer_set_position(packet, mark);
return read_rdata(domains, rdlength, packet, rr);
}
int
print_x25_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
if (!print_string(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_isdn_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
uint16_t length = 0;
const size_t mark = buffer_position(packet);
if(!buffer_available(packet, rdlength))
return MALFORMED;
if (skip_string(packet, rdlength, &length) < 0)
return MALFORMED;
if(rdlength > length) {
if (skip_string(packet, rdlength, &length) < 0
|| rdlength != length)
return MALFORMED;
}
buffer_set_position(packet, mark);
return read_rdata(domains, rdlength, packet, rr);
}
int
print_isdn_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
if (!print_string(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength > length) {
buffer_printf(output, " ");
if (!print_string(output, rr->rdlength, rr->rdata, &length))
return 0;
}
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_rt_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
struct domain *domain;
struct dname_buffer dname;
size_t size;
const size_t mark = buffer_position(packet);
if(!buffer_available(packet, rdlength))
return MALFORMED;
if (rdlength < 2)
return MALFORMED;
buffer_skip(packet, 2);
if (!dname_make_from_packet_buffered(&dname, packet, 1 , 1))
return MALFORMED;
if (rdlength != buffer_position(packet)-mark)
return MALFORMED;
size = sizeof(**rr) + 2 + sizeof(void*);
if (!(*rr = region_alloc(domains->region, size)))
return -1;
domain = domain_table_insert(domains, (void*)&dname);
domain->usage++;
buffer_read_at(packet, mark, (*rr)->rdata, 2);
memcpy((*rr)->rdata + 2, &domain, sizeof(void*));
(*rr)->rdlength = 2 + sizeof(void*);
return rdlength;
}
void
write_rt_rdata(struct query *query, const struct rr *rr)
{
struct domain *domain;
const struct dname *dname;
assert(rr->rdlength == 2 + sizeof(void*));
memcpy(&domain, rr->rdata + 2, sizeof(void*));
dname = domain_dname(domain);
buffer_write(query->packet, rr->rdata, 2);
buffer_write(query->packet, dname_name(dname), dname->name_size);
}
int
print_nsap_rdata(struct buffer *output, const struct rr *rr)
{
buffer_printf(output, "0x");
buffer_print_hex(output, rr->rdata, rr->rdlength);
return 1;
}
int
print_nsap_ptr_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
if(!print_unquoted(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int
print_key_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 4;
if(rr->rdlength < length)
return 0;
buffer_printf(
output, "%" PRIu16 " %" PRIu8 " %" PRIu8 " ",
read_uint16(rr->rdata), rr->rdata[2], rr->rdata[3]);
if (!print_base64(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_px_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
struct domain *map822_domain, *mapx400_domain;
struct dname_buffer map822, mapx400;
size_t size;
const size_t mark = buffer_position(packet);
if (buffer_remaining(packet) < rdlength ||
rdlength < 2)
return MALFORMED;
buffer_skip(packet, 2);
if(!dname_make_from_packet_buffered(&map822, packet,
1 , 1) ||
!dname_make_from_packet_buffered(&mapx400, packet,
1 , 1) ||
rdlength != buffer_position(packet) - mark)
return MALFORMED;
size = sizeof(**rr) + 2 + 2*sizeof(void*);
if (!(*rr = region_alloc(domains->region, size)))
return TRUNCATED;
map822_domain = domain_table_insert(domains, (void*)&map822);
map822_domain->usage++;
mapx400_domain = domain_table_insert(domains, (void*)&mapx400);
mapx400_domain->usage++;
buffer_read_at(packet, mark, (*rr)->rdata, 2);
memcpy((*rr)->rdata+2, &map822_domain, sizeof(void*));
memcpy((*rr)->rdata+2+sizeof(void*), &mapx400_domain, sizeof(void*));
(*rr)->rdlength = 2 + 2*sizeof(void*);
return rdlength;
}
void
write_px_rdata(struct query *query, const struct rr *rr)
{
struct domain *map822_domain, *mapx400_domain;
const struct dname *map822, *mapx400;
memcpy(&map822_domain, rr->rdata + 2, sizeof(void*));
memcpy(&mapx400_domain, rr->rdata + 2 + sizeof(void*), sizeof(void*));
map822 = domain_dname(map822_domain);
mapx400 = domain_dname(mapx400_domain);
buffer_write(query->packet, rr->rdata, 2);
buffer_write(query->packet, dname_name(map822), map822->name_size);
buffer_write(query->packet, dname_name(mapx400), mapx400->name_size);
}
int
print_px_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 2;
assert(rr->rdlength > 3);
buffer_printf(output, "%" PRIu16 " ", read_uint16(rr->rdata));
if (!print_domain(output, rr->rdlength, rr->rdata, &length))
return 0;
buffer_printf(output, " ");
if (!print_domain(output, rr->rdlength, rr->rdata, &length))
return 0;
assert(rr->rdlength == length);
return 1;
}
int
print_gpos_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
if(!print_unquoted(output, rr->rdlength, rr->rdata, &length))
return 0;
buffer_printf(output, " ");
if(!print_unquoted(output, rr->rdlength, rr->rdata, &length))
return 0;
buffer_printf(output, " ");
if(!print_unquoted(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_aaaa_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
if (rdlength != 16)
return MALFORMED;
return read_rdata(domains, rdlength, packet, rr);
}
int
print_aaaa_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
assert(rr->rdlength == 16);
return print_ip6(output, rr->rdlength, rr->rdata, &length);
}
int32_t
read_loc_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
size_t mark;
uint8_t version;
uint16_t size_version_0;
if(!buffer_available(packet, rdlength))
return MALFORMED;
if (rdlength < 1)
return MALFORMED;
mark = buffer_position(packet);
version = buffer_read_u8_at(packet, mark + 0);
size_version_0 = 16u;
if (version == 0 && rdlength != size_version_0)
return MALFORMED;
return read_rdata(domains, rdlength, packet, rr);
}
static void
loc_cm_print(struct buffer* output, uint8_t mantissa, uint8_t exponent)
{
uint8_t i;
if(exponent < 2) {
if(exponent == 1)
mantissa *= 10;
buffer_printf(output, "0.%02ld", (long)mantissa);
return;
}
buffer_printf(output, "%d", (int)mantissa);
for(i=0; i<exponent-2; i++)
buffer_printf(output, "0");
}
int
print_loc_rdata(struct buffer *output, const struct rr *rr)
{
uint8_t version;
uint8_t size;
uint8_t horizontal_precision;
uint8_t vertical_precision;
uint32_t longitude;
uint32_t latitude;
uint32_t altitude;
char northerness;
char easterness;
uint32_t h;
uint32_t m;
double s;
uint32_t equator = (uint32_t)1 << 31;
if(rr->rdlength < 16)
return 0;
version = rr->rdata[0];
if(version != 0)
return 0;
size = rr->rdata[1];
horizontal_precision = rr->rdata[2];
vertical_precision = rr->rdata[3];
latitude = read_uint32(rr->rdata+4);
longitude = read_uint32(rr->rdata+8);
altitude = read_uint32(rr->rdata+12);
if (latitude > equator) {
northerness = 'N';
latitude = latitude - equator;
} else {
northerness = 'S';
latitude = equator - latitude;
}
h = latitude / (1000 * 60 * 60);
latitude = latitude % (1000 * 60 * 60);
m = latitude / (1000 * 60);
latitude = latitude % (1000 * 60);
s = (double) latitude / 1000.0;
buffer_printf(output, "%02u %02u %06.3f %c ",
h, m, s, northerness);
if (longitude > equator) {
easterness = 'E';
longitude = longitude - equator;
} else {
easterness = 'W';
longitude = equator - longitude;
}
h = longitude / (1000 * 60 * 60);
longitude = longitude % (1000 * 60 * 60);
m = longitude / (1000 * 60);
longitude = longitude % (1000 * 60);
s = (double) longitude / (1000.0);
buffer_printf(output, "%02u %02u %06.3f %c ",
h, m, s, easterness);
s = ((double) altitude) / 100;
s -= 100000;
if(altitude%100 != 0)
buffer_printf(output, "%.2f", s);
else
buffer_printf(output, "%.0f", s);
buffer_printf(output, "m ");
loc_cm_print(output, (size & 0xf0) >> 4, size & 0x0f);
buffer_printf(output, "m ");
loc_cm_print(output, (horizontal_precision & 0xf0) >> 4,
horizontal_precision & 0x0f);
buffer_printf(output, "m ");
loc_cm_print(output, (vertical_precision & 0xf0) >> 4,
vertical_precision & 0x0f);
buffer_printf(output, "m");
return 1;
}
int32_t
read_nxt_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
struct domain *domain;
struct dname_buffer dname;
size_t size;
uint16_t bitmap_size;
const size_t mark = buffer_position(packet);
if(!buffer_available(packet, rdlength))
return MALFORMED;
if (!dname_make_from_packet_buffered(&dname, packet, 1, 1))
return MALFORMED;
if(rdlength < buffer_position(packet) - mark)
return MALFORMED;
bitmap_size = rdlength - (buffer_position(packet) - mark);
size = sizeof(**rr) + sizeof(void*) + bitmap_size;
if (!(*rr = region_alloc(domains->region, size)))
return TRUNCATED;
domain = domain_table_insert(domains, (void*)&dname);
domain->usage++;
memcpy((*rr)->rdata, &domain, sizeof(void*));
if(bitmap_size != 0)
buffer_read(packet, (*rr)->rdata + sizeof(void*), bitmap_size);
(*rr)->rdlength = sizeof(void*) + bitmap_size;
return rdlength;
}
void
write_nxt_rdata(struct query *query, const struct rr *rr)
{
struct domain *domain;
const struct dname *dname;
assert(rr->rdlength >= sizeof(void*));
memcpy(&domain, rr->rdata, sizeof(void*));
dname = domain_dname(domain);
buffer_write(query->packet, dname_name(dname), dname->name_size);
if(rr->rdlength - sizeof(void*) != 0)
buffer_write(query->packet, rr->rdata + sizeof(void*),
rr->rdlength - sizeof(void*));
}
int
print_nxt_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
int bitmap_size;
const uint8_t* bitmap;
assert(rr->rdlength >= sizeof(void*));
if (!print_domain(output, rr->rdlength, rr->rdata, &length))
return 0;
bitmap_size = rr->rdlength - length;
bitmap = rr->rdata + length;
for (int type = 0; type < bitmap_size * 8; type++) {
if (get_bit(bitmap, type)) {
buffer_printf(output, " %s", rrtype_to_string(type));
}
}
return 1;
}
int
print_eid_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
if(!print_base16(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int
print_nimloc_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
if(!print_base16(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_srv_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
struct domain *domain;
struct dname_buffer dname;
size_t size;
const size_t mark = buffer_position(packet);
if (buffer_remaining(packet) < rdlength || rdlength < 6)
return MALFORMED;
buffer_skip(packet, 6);
if (!dname_make_from_packet_buffered(&dname, packet,
1 , 1) ||
rdlength != buffer_position(packet)-mark)
return MALFORMED;
size = sizeof(**rr) + 6 + sizeof(void*);
if (!(*rr = region_alloc(domains->region, size)))
return TRUNCATED;
domain = domain_table_insert(domains, (void*)&dname);
domain->usage++;
buffer_read_at(packet, mark, (*rr)->rdata, 6);
memcpy((*rr)->rdata + 6, &domain, sizeof(void*));
(*rr)->rdlength = 6 + sizeof(void*);
return rdlength;
}
void
write_srv_rdata(struct query *query, const struct rr *rr)
{
struct domain *domain;
const struct dname *dname;
assert(rr->rdlength == 6 + sizeof(void*));
memcpy(&domain, rr->rdata + 6, sizeof(void*));
dname = domain_dname(domain);
buffer_write(query->packet, rr->rdata, 6);
buffer_write(query->packet, dname_name(dname), dname->name_size);
}
int
print_srv_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 6;
assert(rr->rdlength > length);
buffer_printf(
output, "%" PRIu16 " %" PRIu16 " %" PRIu16 " ",
read_uint16(rr->rdata), read_uint16(rr->rdata+2),
read_uint16(rr->rdata+4));
if (!print_domain(output, rr->rdlength, rr->rdata, &length))
return 0;
assert(rr->rdlength == length);
return 1;
}
int
print_atma_rdata(struct buffer *output, const struct rr *rr)
{
uint8_t format;
if(rr->rdlength < 1)
return 0;
format = rr->rdata[0];
if(format == 0) {
uint16_t length = 1;
if (!print_base16(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
} else if(format == 1) {
buffer_printf(output, "+");
for (size_t i = 1; i < rr->rdlength; i++) {
char ch = (char)rr->rdata[i];
if(!isdigit((unsigned char)ch))
return 0;
buffer_printf(output, "%c", ch);
}
return 1;
}
return 0;
}
int32_t
read_naptr_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
struct domain *domain;
struct dname_buffer dname;
uint16_t length = 4;
size_t size;
const size_t mark = buffer_position(packet);
if (buffer_remaining(packet) < rdlength ||
rdlength < length)
return MALFORMED;
buffer_skip(packet, 4);
if(skip_string(packet, rdlength, &length) < 0 ||
skip_string(packet, rdlength, &length) < 0 ||
skip_string(packet, rdlength, &length) < 0 ||
!dname_make_from_packet_buffered(&dname, packet, 1, 1) ||
rdlength != buffer_position(packet) - mark)
return MALFORMED;
size = sizeof(**rr) + length + sizeof(void*);
if (!(*rr = region_alloc(domains->region, size)))
return TRUNCATED;
domain = domain_table_insert(domains, (void*)&dname);
domain->usage++;
buffer_read_at(packet, mark, (*rr)->rdata, length);
memcpy((*rr)->rdata + length, &domain, sizeof(void*));
(*rr)->rdlength = length + sizeof(void*);
return rdlength;
}
void
write_naptr_rdata(struct query *query, const struct rr *rr)
{
struct domain *domain;
const struct dname *dname;
uint16_t length;
assert(rr->rdlength >= 7 + sizeof(void*));
length = rr->rdlength - sizeof(void*);
memcpy(&domain, rr->rdata + length, sizeof(void*));
dname = domain_dname(domain);
buffer_write(query->packet, rr->rdata, length);
buffer_write(query->packet, dname_name(dname), dname->name_size);
}
int
print_naptr_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 4;
assert(rr->rdlength >= 7 + sizeof(void*));
buffer_printf(
output, "%" PRIu16 " %" PRIu16 " ",
read_uint16(rr->rdata), read_uint16(rr->rdata+2));
if (!print_string(output, rr->rdlength, rr->rdata, &length))
return 0;
buffer_printf(output, " ");
if (!print_string(output, rr->rdlength, rr->rdata, &length))
return 0;
buffer_printf(output, " ");
if (!print_string(output, rr->rdlength, rr->rdata, &length))
return 0;
buffer_printf(output, " ");
if (!print_domain(output, rr->rdlength, rr->rdata, &length))
return 0;
assert(rr->rdlength == length);
return 1;
}
int32_t
read_kx_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
struct domain *domain;
struct dname_buffer dname;
const size_t mark = buffer_position(packet);
size_t size;
if(buffer_remaining(packet) < rdlength || rdlength < 2)
return MALFORMED;
buffer_skip(packet, 2);
if(!dname_make_from_packet_buffered(&dname, packet,
1 , 1) ||
rdlength != buffer_position(packet) - mark)
return MALFORMED;
size = sizeof(**rr) + 2 + sizeof(void*);
if (!(*rr = region_alloc(domains->region, size)))
return TRUNCATED;
domain = domain_table_insert(domains, (void*)&dname);
domain->usage++;
buffer_read_at(packet, mark, (*rr)->rdata, 2);
memcpy((*rr)->rdata + 2, &domain, sizeof(void*));
(*rr)->rdlength = 2 + sizeof(void*);
return rdlength;
}
void
write_kx_rdata(struct query *query, const struct rr *rr)
{
struct domain *domain;
const struct dname *dname;
assert(rr->rdlength == 2 + sizeof(void*));
memcpy(&domain, rr->rdata + 2, sizeof(void*));
dname = domain_dname(domain);
buffer_write(query->packet, rr->rdata, 2);
buffer_write(query->packet, dname_name(dname), dname->name_size);
}
int32_t
read_cert_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
if (rdlength < 5)
return MALFORMED;
return read_rdata(domains, rdlength, packet, rr);
}
int
print_cert_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
if(rr->rdlength < 5)
return 0;
if(!print_certificate_type(output, rr->rdlength, rr->rdata, &length))
return 0;
buffer_printf(output, " %" PRIu16 " %" PRIu8 " ",
read_uint16(rr->rdata+2), rr->rdata[4]);
length += 3;
if (!print_base64(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int
print_sink_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 2;
if(rr->rdlength < 2)
return 0;
buffer_printf(output, "%" PRIu8 " %" PRIu8 " ",
rr->rdata[0], rr->rdata[1]);
if (!print_base64(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_apl_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
uint16_t length = 0;
const uint8_t *rdata = buffer_current(packet);
if (buffer_remaining(packet) < rdlength)
return MALFORMED;
while (rdlength - length >= 4) {
uint8_t afdlength = rdata[length + 3] & APL_LENGTH_MASK;
uint16_t afam = read_uint16(rdata + length);
if (rdlength - (length + 4) < afdlength ||
(afam == 1 && afdlength > 4) ||
(afam == 2 && afdlength > 16))
return MALFORMED;
length += 4 + afdlength;
}
if (length != rdlength)
return MALFORMED;
return read_rdata(domains, rdlength, packet, rr);
}
static int
print_apl(struct buffer *output, size_t rdlength, const uint8_t *rdata,
uint16_t *offset)
{
size_t size = rdlength - *offset;
uint16_t address_family;
uint8_t prefix, length, negated;
int af;
char text_address[INET6_ADDRSTRLEN + 1];
uint8_t address[16];
if (rdlength < *offset || size < 4)
return 0;
address_family = read_uint16(rdata + *offset);
prefix = rdata[*offset + 2];
length = rdata[*offset + 3] & APL_LENGTH_MASK;
negated = rdata[*offset + 3] & APL_NEGATION_MASK;
af = -1;
switch (address_family) {
case 1: af = AF_INET;
if(length > 4)
return 0;
break;
case 2: af = AF_INET6;
if(length > 16)
return 0;
break;
}
if (af == -1 || size - 4 < length)
return 0;
memset(address, 0, sizeof(address));
if(length > sizeof(address))
return 0;
memmove(address, rdata + *offset + 4, length);
if (!inet_ntop(af, address, text_address, sizeof(text_address)))
return 0;
buffer_printf(
output, "%s%" PRIu16 ":%s/%" PRIu8,
(negated ? "!" : ""), address_family, text_address, prefix);
*offset += 4 + length;
return 1;
}
int
print_apl_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
while (length < rr->rdlength) {
if(length != 0)
buffer_printf(output, " ");
if (!print_apl(output, rr->rdlength, rr->rdata, &length))
return 0;
}
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_ds_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
if (rdlength < 4)
return MALFORMED;
return read_rdata(domains, rdlength, packet, rr);
}
int
print_ds_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 4;
if(rr->rdlength < length)
return 0;
buffer_printf(
output, "%" PRIu16 " %" PRIu8 " %" PRIu8 " ",
read_uint16(rr->rdata), rr->rdata[2], rr->rdata[3]);
if (!print_base16(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_sshfp_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
if (rdlength < 2)
return MALFORMED;
return read_rdata(domains, rdlength, packet, rr);
}
int
print_sshfp_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 2;
uint8_t algorithm, ftype;
if(rr->rdlength < length)
return 0;
algorithm = rr->rdata[0];
ftype = rr->rdata[1];
buffer_printf(output, "%" PRIu8 " %" PRIu8 " ", algorithm, ftype);
if (!print_base16(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_ipseckey_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
struct dname_buffer gateway;
const uint8_t *gateway_rdata;
uint8_t gateway_length = 0;
const size_t mark = buffer_position(packet);
uint16_t keylen;
if (buffer_remaining(packet) < rdlength || rdlength < 3)
return MALFORMED;
buffer_skip(packet, 3);
switch (buffer_read_u8_at(packet, mark + 1)) {
case IPSECKEY_NOGATEWAY:
gateway_length = 0;
gateway_rdata = NULL;
break;
case IPSECKEY_IP4:
gateway_length = 4;
gateway_rdata = buffer_current(packet);
if (rdlength < 3 + gateway_length)
return MALFORMED;
buffer_skip(packet, gateway_length);
break;
case IPSECKEY_IP6:
gateway_length = 16;
gateway_rdata = buffer_current(packet);
if (rdlength < 3 + gateway_length)
return MALFORMED;
buffer_skip(packet, gateway_length);
break;
case IPSECKEY_DNAME:
if (!dname_make_from_packet_buffered(&gateway, packet,
1 , 0))
return MALFORMED;
if(rdlength < buffer_position(packet) - mark)
return MALFORMED;
gateway_length = gateway.dname.name_size;
gateway_rdata = dname_name((void*)&gateway);
break;
default:
return MALFORMED;
}
keylen = rdlength - (buffer_position(packet)-mark);
if (!(*rr = region_alloc(domains->region,
sizeof(**rr) + 3 + gateway_length + keylen)))
return TRUNCATED;
buffer_read_at(packet, mark, (*rr)->rdata, 3);
if(gateway_rdata)
memcpy((*rr)->rdata + 3, gateway_rdata, gateway_length);
if(keylen != 0)
buffer_read(packet, (*rr)->rdata + 3 + gateway_length, keylen);
(*rr)->rdlength = 3 + gateway_length + keylen;
return rdlength;
}
int
print_ipseckey_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 3;
uint8_t gateway_type;
if(rr->rdlength < length)
return 0;
buffer_printf(
output, "%" PRIu8 " %" PRIu8 " %" PRIu8 " ",
rr->rdata[0], rr->rdata[1], rr->rdata[2]);
gateway_type = rr->rdata[1];
switch (gateway_type) {
case IPSECKEY_NOGATEWAY:
buffer_printf(output, ".");
break;
case IPSECKEY_IP4:
if (!print_ip4(output, rr->rdlength, rr->rdata, &length))
return 0;
break;
case IPSECKEY_IP6:
if (!print_ip6(output, rr->rdlength, rr->rdata, &length))
return 0;
break;
case IPSECKEY_DNAME:
if (!print_name_literal(output, rr->rdlength, rr->rdata,
&length))
return 0;
break;
default:
return 0;
}
if(rr->rdlength > length) {
buffer_printf(output, " ");
if (!print_base64(output, rr->rdlength, rr->rdata, &length))
return 0;
}
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
ipseckey_gateway_length(uint16_t rdlength, const uint8_t *rdata,
uint16_t offset, struct domain** domain)
{
uint8_t gateway_type;
*domain = NULL;
if(rdlength < 3 || offset < 3)
return -1;
gateway_type = rdata[1];
switch(gateway_type) {
case IPSECKEY_NOGATEWAY:
return 0;
case IPSECKEY_IP4:
return 4;
case IPSECKEY_IP6:
return 16;
case IPSECKEY_DNAME:
return buf_dname_length(rdata+offset, rdlength-offset);
default:
break;
}
return -1;
}
int32_t
read_rrsig_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
struct dname_buffer signer;
const size_t mark = buffer_position(packet);
uint16_t memrdlen, b64len;
if (buffer_remaining(packet) < rdlength || rdlength < 18)
return MALFORMED;
buffer_skip(packet, 18);
if (!dname_make_from_packet_buffered(&signer, packet,
1 , 0))
return MALFORMED;
if (rdlength < buffer_position(packet) - mark)
return MALFORMED;
memrdlen = 18 + signer.dname.name_size;
b64len = rdlength - (buffer_position(packet) - mark);
if (!(*rr = region_alloc(domains->region, sizeof(**rr) + memrdlen + b64len)))
return TRUNCATED;
buffer_read_at(packet, mark, (*rr)->rdata, 18);
memcpy((*rr)->rdata + 18, dname_name((void*)&signer),
signer.dname.name_size);
if(b64len != 0)
buffer_read(packet, (*rr)->rdata+memrdlen, b64len);
(*rr)->rdlength = memrdlen + b64len;
return rdlength;
}
int
print_rrsig_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 8;
if(rr->rdlength < 18)
return 0;
buffer_printf(
output, "%s %" PRIu8 " %" PRIu8 " %" PRIu32 " ",
rrtype_to_string(read_uint16(rr->rdata)), rr->rdata[2],
rr->rdata[3], read_uint32(rr->rdata+4));
if (!print_time(output, rr->rdlength, rr->rdata, &length))
return 0;
buffer_printf(output, " ");
if (!print_time(output, rr->rdlength, rr->rdata, &length))
return 0;
buffer_printf(output, " %" PRIu16 " ", read_uint16(rr->rdata+length));
length += 2;
if (!print_name_literal(output, rr->rdlength, rr->rdata, &length))
return 0;
buffer_printf(output, " ");
if (!print_base64(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_nsec_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
struct dname_buffer next;
uint16_t length, memrdlen, bitmaplen;
size_t bitmapmark;
const size_t mark = buffer_position(packet);
if(buffer_remaining(packet) < rdlength ||
!dname_make_from_packet_buffered(&next, packet,
1 , 0
) ||
rdlength < buffer_position(packet) - mark)
return MALFORMED;
bitmapmark = buffer_position(packet);
length = bitmapmark - mark;
if (skip_nsec(packet, rdlength, &length) < 0
|| rdlength != length)
return MALFORMED;
bitmaplen = buffer_position(packet) - bitmapmark;
memrdlen = next.dname.name_size + bitmaplen;
if (!(*rr = region_alloc(domains->region, sizeof(**rr) + memrdlen)))
return TRUNCATED;
memcpy((*rr)->rdata, dname_name((void*)&next), next.dname.name_size);
if(bitmaplen != 0)
buffer_read_at(packet, bitmapmark,
(*rr)->rdata + next.dname.name_size, bitmaplen);
(*rr)->rdlength = memrdlen;
return rdlength;
}
int
print_nsec_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
if (!print_name_literal(output, rr->rdlength, rr->rdata, &length))
return 0;
buffer_printf(output, " ");
if (!print_nsec_bitmap(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_dnskey_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
if (rdlength < 4)
return MALFORMED;
return read_rdata(domains, rdlength, packet, rr);
}
int
print_dnskey_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 4;
if(rr->rdlength < length)
return 0;
buffer_printf(
output, "%" PRIu16 " %" PRIu8 " %" PRIu8 " ",
read_uint16(rr->rdata), rr->rdata[2], rr->rdata[3]);
if (!print_base64(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_dhcid_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
if (rdlength < 3)
return MALFORMED;
return read_rdata(domains, rdlength, packet, rr);
}
int
print_dhcid_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
if (!print_base64(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_nsec3_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
uint16_t length = 4;
const size_t mark = buffer_position(packet);
if (buffer_remaining(packet) < rdlength || rdlength < length)
return MALFORMED;
buffer_skip(packet, length);
if (skip_string(packet, rdlength, &length) < 0 ||
skip_string(packet, rdlength, &length) < 0 ||
skip_nsec(packet, rdlength, &length) < 0 ||
rdlength != length)
return MALFORMED;
buffer_set_position(packet, mark);
return read_rdata(domains, rdlength, packet, rr);
}
int
print_nsec3_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 4;
if(rr->rdlength < length)
return 0;
buffer_printf(
output, "%" PRIu8 " %" PRIu8 " %" PRIu16 " ",
rr->rdata[0], rr->rdata[1], read_uint16(rr->rdata + 2));
if (!print_salt(output, rr->rdlength, rr->rdata, &length))
return 0;
buffer_printf(output, " ");
if (!print_base32(output, rr->rdlength, rr->rdata, &length))
return 0;
buffer_printf(output, " ");
if (!print_nsec_bitmap(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_nsec3param_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
uint16_t length = 4;
const size_t mark = buffer_position(packet);
if (buffer_remaining(packet) < rdlength || rdlength < length)
return MALFORMED;
buffer_skip(packet, length);
if (skip_string(packet, rdlength, &length) < 0 ||
rdlength != length)
return MALFORMED;
buffer_set_position(packet, mark);
return read_rdata(domains, rdlength, packet, rr);
}
int
print_nsec3param_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 4;
if(rr->rdlength < length)
return 0;
buffer_printf(
output, "%" PRIu8 " %" PRIu8 " %" PRIu16 " ",
rr->rdata[0], rr->rdata[1], read_uint16(rr->rdata + 2));
if (!print_salt(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_tlsa_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
if (rdlength < 3)
return MALFORMED;
return read_rdata(domains, rdlength, packet, rr);
}
int
print_tlsa_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 3;
if(rr->rdlength < length)
return 0;
buffer_printf(
output, "%" PRIu8 " %" PRIu8 " %" PRIu8 " ",
rr->rdata[0], rr->rdata[1], rr->rdata[2]);
if (!print_base16(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_hip_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
if (rdlength < 4)
return MALFORMED;
return read_rdata(domains, rdlength, packet, rr);
}
int
print_hip_rdata(struct buffer *output, const struct rr *rr)
{
uint8_t hit_length, pk_algorithm;
uint16_t pk_length;
uint16_t length = 4;
if(rr->rdlength < length)
return 0;
hit_length = rr->rdata[0];
pk_algorithm = rr->rdata[1];
pk_length = read_uint16(rr->rdata+2);
if(4 + (uint32_t)hit_length + (uint32_t)pk_length > (uint32_t)rr->rdlength)
return 0;
buffer_printf(output, "%" PRIu8 " ", pk_algorithm);
if(!print_base16(output, length+hit_length, rr->rdata, &length))
return 0;
buffer_printf(output, " ");
if(!print_base64(output, length+pk_length, rr->rdata, &length))
return 0;
while(length < rr->rdlength) {
buffer_printf(output, " ");
if(!print_name_literal(output, rr->rdlength, rr->rdata,
&length))
return 0;
}
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_rkey_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
if (rdlength < 4)
return MALFORMED;
return read_rdata(domains, rdlength, packet, rr);
}
int
print_rkey_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 4;
if(rr->rdlength < length)
return 0;
buffer_printf(
output, "%" PRIu16 " %" PRIu8 " %" PRIu8 " ",
read_uint16(rr->rdata), rr->rdata[2], rr->rdata[3]);
if (!print_base64(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_talink_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
struct dname_buffer prev, next;
const size_t mark = buffer_position(packet);
if(!buffer_available(packet, rdlength))
return MALFORMED;
if(!dname_make_from_packet_buffered(&prev, packet,
1 , 0))
return MALFORMED;
if(buffer_position(packet)-mark > rdlength)
return MALFORMED;
if(!dname_make_from_packet_buffered(&next, packet,
1 , 0))
return MALFORMED;
if(buffer_position(packet)-mark != rdlength)
return MALFORMED;
if (!(*rr = region_alloc(domains->region,
sizeof(**rr) + prev.dname.name_size + next.dname.name_size)))
return TRUNCATED;
memcpy((*rr)->rdata, dname_name((void*)&prev), prev.dname.name_size);
memcpy((*rr)->rdata + prev.dname.name_size, dname_name((void*)&next),
next.dname.name_size);
(*rr)->rdlength = prev.dname.name_size + next.dname.name_size;
return rdlength;
}
int
print_talink_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
if(!print_name_literal(output, rr->rdlength, rr->rdata, &length))
return 0;
buffer_printf(output, " ");
if(!print_name_literal(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int
print_openpgpkey_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
if (!print_base64(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_csync_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
if (rdlength < 6)
return MALFORMED;
return read_rdata(domains, rdlength, packet, rr);
}
int
print_csync_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 6;
if(rr->rdlength < length)
return 0;
buffer_printf(
output, "%" PRIu32 " %" PRIu16 " ",
read_uint32(rr->rdata), read_uint16(rr->rdata + 4));
if (!print_nsec_bitmap(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_zonemd_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
if (rdlength < 6)
return MALFORMED;
return read_rdata(domains, rdlength, packet, rr);
}
int
print_zonemd_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 6;
if(rr->rdlength < length)
return 0;
buffer_printf(
output, "%" PRIu32 " %" PRIu8 " %" PRIu8 " ",
read_uint32(rr->rdata), rr->rdata[4], rr->rdata[5]);
if (!print_base16(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_svcb_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
struct domain *domain;
struct dname_buffer target;
uint16_t length = 2, svcparams_length = 0;
size_t size;
const size_t mark = buffer_position(packet);
if (buffer_remaining(packet) < rdlength || rdlength < length)
return MALFORMED;
buffer_skip(packet, length);
if (!dname_make_from_packet_buffered(&target, packet,
1 , 1))
return MALFORMED;
if(rdlength < buffer_position(packet) - mark)
return MALFORMED;
length = buffer_position(packet)-mark;
svcparams_length = rdlength - length;
buffer_skip(packet, svcparams_length);
size = sizeof(**rr) + 2 + sizeof(void*) + svcparams_length;
if (!(*rr = region_alloc(domains->region, size)))
return TRUNCATED;
domain = domain_table_insert(domains, (void*)&target);
domain->usage++;
buffer_read_at(packet, mark, (*rr)->rdata, 2);
memcpy((*rr)->rdata + 2, &domain, sizeof(void*));
if(svcparams_length != 0)
buffer_read_at(packet, mark + length,
(*rr)->rdata + 2 + sizeof(void*), svcparams_length);
(*rr)->rdlength = 2 + sizeof(void*) + svcparams_length;
return rdlength;
}
void
write_svcb_rdata(struct query *query, const struct rr *rr)
{
struct domain *domain;
const struct dname *target;
uint8_t length;
assert(rr->rdlength >= 2 + sizeof(void*));
memcpy(&domain, rr->rdata + 2, sizeof(void*));
target = domain_dname(domain);
buffer_write(query->packet, rr->rdata, 2);
buffer_write(query->packet, dname_name(target), target->name_size);
length = 2 + sizeof(void*);
if(rr->rdlength > length)
buffer_write(query->packet, rr->rdata + length,
rr->rdlength - length);
}
int
print_svcb_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 2;
assert(rr->rdlength > length);
buffer_printf(output, "%" PRIu16 " ", read_uint16(rr->rdata));
if (!print_domain(output, rr->rdlength, rr->rdata, &length))
return 0;
while (length < rr->rdlength) {
buffer_printf(output, " ");
if (!print_svcparam(output, rr->rdlength, rr->rdata, &length))
return 0;
}
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_dsync_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
struct dname_buffer target;
uint16_t length = 5;
const size_t mark = buffer_position(packet);
if (buffer_remaining(packet) < rdlength || rdlength < length)
return MALFORMED;
buffer_skip(packet, length);
if(!dname_make_from_packet_buffered(&target, packet,
1 , 0) ||
rdlength != buffer_position(packet) - mark)
return MALFORMED;
length += target.dname.name_size;
if (!(*rr = region_alloc(domains->region, sizeof(**rr)+length)))
return TRUNCATED;
buffer_read_at(packet, mark, (*rr)->rdata, 5);
memcpy((*rr)->rdata + 5, dname_name((void*)&target),
target.dname.name_size);
(*rr)->rdlength = length;
return rdlength;
}
int
print_dsync_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 5;
if(rr->rdlength < length)
return 0;
buffer_printf(output, "%s %" PRIu8 " %" PRIu16 " ",
rrtype_to_string(read_uint16(rr->rdata)), rr->rdata[2],
read_uint16(rr->rdata+3));
if(!print_name_literal(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_nid_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
if (rdlength != 10)
return MALFORMED;
return read_rdata(domains, rdlength, packet, rr);
}
int
print_nid_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 2;
if(rr->rdlength != 10)
return 0;
buffer_printf(output, "%" PRIu16 " ", read_uint16(rr->rdata));
if (!print_ilnp64(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_l32_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
if (rdlength != 6)
return MALFORMED;
return read_rdata(domains, rdlength, packet, rr);
}
int
print_l32_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 2;
if(rr->rdlength != 6)
return 0;
buffer_printf(output, "%" PRIu16 " ", read_uint16(rr->rdata));
if (!print_ip4(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_l64_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
if (rdlength != 10)
return MALFORMED;
return read_rdata(domains, rdlength, packet, rr);
}
int
print_l64_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 2;
if(rr->rdlength != 10)
return 0;
buffer_printf(output, "%" PRIu16 " ", read_uint16(rr->rdata));
if (!print_ilnp64(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_lp_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
struct domain *domain;
struct dname_buffer target;
size_t size;
const size_t mark = buffer_position(packet);
if (buffer_remaining(packet) < rdlength || rdlength < 2)
return MALFORMED;
buffer_skip(packet, 2);
if (!dname_make_from_packet_buffered(&target, packet,
1 , 1) ||
rdlength != buffer_position(packet) - mark)
return MALFORMED;
size = sizeof(**rr) + 2 + sizeof(void*);
if (!(*rr = region_alloc(domains->region, size)))
return TRUNCATED;
domain = domain_table_insert(domains, (void*)&target);
domain->usage++;
buffer_read_at(packet, mark, (*rr)->rdata, 2);
memcpy((*rr)->rdata + 2, &domain, sizeof(void*));
(*rr)->rdlength = 2 + sizeof(void*);
return rdlength;
}
void
write_lp_rdata(struct query *query, const struct rr *rr)
{
struct domain *domain;
const struct dname *dname;
assert(rr->rdlength == 2 + sizeof(void*));
memcpy(&domain, rr->rdata + 2, sizeof(void*));
dname = domain_dname(domain);
buffer_write(query->packet, rr->rdata, 2);
buffer_write(query->packet, dname_name(dname), dname->name_size);
}
int
print_lp_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 2;
assert(rr->rdlength == 2 + sizeof(void*));
buffer_printf(output, "%" PRIu16 " ", read_uint16(rr->rdata));
if (!print_domain(output, rr->rdlength, rr->rdata, &length))
return 0;
assert(rr->rdlength == length);
return 1;
}
int32_t
read_eui48_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
if (rdlength != 6)
return MALFORMED;
return read_rdata(domains, rdlength, packet, rr);
}
int
print_eui48_rdata(struct buffer *output, const struct rr *rr)
{
const uint8_t *x = rr->rdata;
if(rr->rdlength != 6)
return 0;
buffer_printf(output, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
x[0], x[1], x[2], x[3], x[4], x[5]);
return 1;
}
int32_t
read_eui64_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
if (rdlength != 8)
return MALFORMED;
return read_rdata(domains, rdlength, packet, rr);
}
int
print_eui64_rdata(struct buffer *output, const struct rr *rr)
{
const uint8_t *x = rr->rdata;
if(rr->rdlength != 8)
return 0;
buffer_printf(output, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7]);
return 1;
}
int32_t
read_uri_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
if (rdlength < 4)
return MALFORMED;
return read_rdata(domains, rdlength, packet, rr);
}
int
print_uri_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 4;
if(rr->rdlength < length)
return 0;
buffer_printf(
output, "%" PRIu16 " %" PRIu16 " ",
read_uint16(rr->rdata), read_uint16(rr->rdata + 2));
if(!print_text(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int
print_resinfo_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 0;
if(!print_unquoteds(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_caa_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
const size_t mark = buffer_position(packet);
uint16_t length = 1;
if (buffer_remaining(packet) < rdlength || rdlength < 2)
return MALFORMED;
buffer_skip(packet, 1);
if (skip_string(packet, rdlength, &length) < 0 || rdlength < length)
return MALFORMED;
buffer_set_position(packet, mark);
return read_rdata(domains, rdlength, packet, rr);
}
int
print_caa_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 1;
if(rr->rdlength < 2)
return 0;
buffer_printf(output, "%" PRIu8 " ", rr->rdata[0]);
length = 2 + rr->rdata[1];
if (rr->rdlength < length)
return 0;
for (uint16_t i = 2; i < length; ++i) {
char ch = (char) rr->rdata[i];
if (isdigit((unsigned char)ch) || islower((unsigned char)ch))
buffer_printf(output, "%c", ch);
else return 0;
}
buffer_printf(output, " ");
if (!print_text(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int
print_doa_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 9;
if(rr->rdlength < length)
return 0;
buffer_printf(output, "%" PRIu32 " %" PRIu32 " %" PRIu8 " ",
read_uint32(rr->rdata), read_uint32(rr->rdata+4),
rr->rdata[8]);
if(!print_string(output, rr->rdlength, rr->rdata, &length))
return 0;
buffer_printf(output, " ");
if(rr->rdlength == length) {
buffer_printf(output, "-");
} else {
if(!print_base64(output, rr->rdlength, rr->rdata, &length))
return 0;
}
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
read_amtrelay_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
struct dname_buffer relay;
const uint8_t *relay_rdata;
uint8_t relay_length = 0;
const size_t mark = buffer_position(packet);
if (buffer_remaining(packet) < rdlength || rdlength < 2)
return MALFORMED;
buffer_skip(packet, 2);
switch (buffer_read_u8_at(packet, mark + 1)&AMTRELAY_TYPE_MASK) {
case AMTRELAY_NOGATEWAY:
relay_length = 0;
relay_rdata = NULL;
break;
case AMTRELAY_IP4:
relay_length = 4;
relay_rdata = buffer_current(packet);
if (rdlength < 2 + relay_length)
return MALFORMED;
buffer_skip(packet, relay_length);
break;
case AMTRELAY_IP6:
relay_length = 16;
relay_rdata = buffer_current(packet);
if (rdlength < 2 + relay_length)
return MALFORMED;
buffer_skip(packet, relay_length);
break;
case AMTRELAY_DNAME:
if(!dname_make_from_packet_buffered(&relay, packet,
1 , 0))
return MALFORMED;
if(rdlength < buffer_position(packet) - mark)
return MALFORMED;
relay_length = relay.dname.name_size;
relay_rdata = dname_name((void*)&relay);
break;
default:
return MALFORMED;
}
if(rdlength != buffer_position(packet) - mark)
return MALFORMED;
if (!(*rr = region_alloc(domains->region,
sizeof(**rr) + 2 + relay_length)))
return TRUNCATED;
buffer_read_at(packet, mark, (*rr)->rdata, 2);
if(relay_rdata)
memcpy((*rr)->rdata + 2, relay_rdata, relay_length);
(*rr)->rdlength = 2 + relay_length;
return rdlength;
}
int
print_amtrelay_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 2;
uint8_t relay_type;
if(rr->rdlength < length)
return 0;
relay_type = rr->rdata[1]&AMTRELAY_TYPE_MASK;
buffer_printf(output, "%" PRIu8 " %c %" PRIu8,
rr->rdata[0],
(rr->rdata[1] & AMTRELAY_DISCOVERY_OPTIONAL_MASK ? '1' : '0'),
relay_type);
switch(relay_type) {
case AMTRELAY_NOGATEWAY:
buffer_printf(output, " .");
break;
case AMTRELAY_IP4:
buffer_printf(output, " ");
if(!print_ip4(output, rr->rdlength, rr->rdata, &length))
return 0;
break;
case AMTRELAY_IP6:
buffer_printf(output, " ");
if(!print_ip6(output, rr->rdlength, rr->rdata, &length))
return 0;
break;
case AMTRELAY_DNAME:
buffer_printf(output, " ");
if(!print_name_literal(output, rr->rdlength, rr->rdata,
&length))
return 0;
break;
default:
return 0;
}
if(rr->rdlength != length)
return 0;
return 1;
}
int32_t
amtrelay_relay_length(uint16_t rdlength, const uint8_t *rdata, uint16_t offset,
struct domain** domain)
{
uint8_t relay_type;
*domain = NULL;
if(rdlength < 2 || offset < 2)
return -1;
relay_type = rdata[1]&AMTRELAY_TYPE_MASK;
switch(relay_type) {
case AMTRELAY_NOGATEWAY:
return 0;
case AMTRELAY_IP4:
return 4;
case AMTRELAY_IP6:
return 16;
case AMTRELAY_DNAME:
return buf_dname_length(rdata+offset, rdlength-offset);
default:
break;
}
return -1;
}
int
print_ipn_rdata(struct buffer *output, const struct rr *rr)
{
uint64_t data;
if(rr->rdlength < sizeof(data))
return 0;
data = read_uint64(rr->rdata);
buffer_printf(output, "%llu", (unsigned long long) data);
return 1;
}
int32_t
read_dlv_rdata(struct domain_table *domains, uint16_t rdlength,
struct buffer *packet, struct rr **rr)
{
if (rdlength < 4)
return MALFORMED;
return read_rdata(domains, rdlength, packet, rr);
}
int
print_dlv_rdata(struct buffer *output, const struct rr *rr)
{
uint16_t length = 4;
if(rr->rdlength < length)
return 0;
buffer_printf(
output, "%" PRIu16 " %" PRIu8 " %" PRIu8 " ",
read_uint16(rr->rdata), rr->rdata[2], rr->rdata[3]);
if (!print_base16(output, rr->rdlength, rr->rdata, &length))
return 0;
if(rr->rdlength != length)
return 0;
return 1;
}
int
print_rdata(buffer_type *output, const nsd_type_descriptor_type *descriptor,
const rr_type *rr)
{
size_t saved_position = buffer_position(output);
if(!(rr->type == TYPE_APL && rr->rdlength == 0))
buffer_printf(output, "\t");
if(!descriptor->print_rdata(output, rr)) {
buffer_set_position(output, saved_position);
return 0;
}
return 1;
}
static int
compare_bytestring(const uint8_t* b1, uint16_t len1, const uint8_t* b2,
uint16_t len2)
{
uint16_t blen;
int res;
if(len1 == 0 && len2 == 0)
return 0;
if(len1 == 0 && len2 != 0)
return -1;
if(len1 != 0 && len2 == 0)
return 1;
blen = len1;
if(len2 < blen)
blen = len2;
res = memcmp(b1, b2, blen);
if(res != 0)
return res;
if(len1 < len2)
return -1;
if(len1 > len2)
return 1;
return 0;
}
int
equal_rr_rdata(const nsd_type_descriptor_type *descriptor,
const struct rr *rr1, const struct rr *rr2)
{
size_t i;
uint16_t offset = 0;
int res;
if(!descriptor->has_references) {
res = compare_bytestring(rr1->rdata, rr1->rdlength,
rr2->rdata, rr2->rdlength);
if(res != 0)
return 0;
return 1;
}
for(i=0; i < descriptor->rdata.length; i++) {
uint16_t field_len1, field_len2;
struct domain* domain1, *domain2;
int malf1 = 0, malf2 = 0;
if((rr1->rdlength == offset || rr2->rdlength == offset) &&
descriptor->rdata.fields[i].is_optional) {
if(rr1->rdlength == rr2->rdlength)
return 1;
else
return 0;
}
if(!lookup_rdata_field_entry(descriptor, i, rr1, offset,
&field_len1, &domain1))
malf1 = 1;
if(!lookup_rdata_field_entry(descriptor, i, rr2, offset,
&field_len2, &domain2))
malf2 = 1;
if(malf1 || malf2) {
if(malf1 && malf2)
return 1;
else
return 0;
}
if(domain1 && !domain2)
return 0;
if(!domain1 && domain2)
return 0;
if(domain1 && domain2) {
res = dname_compare(domain_dname(domain1),
domain_dname(domain2));
if(res != 0)
return 0;
} else {
res = compare_bytestring(rr1->rdata + offset,
field_len1, rr2->rdata + offset, field_len2);
if(res != 0)
return 0;
}
offset += field_len1;
}
return 1;
}
int
equal_rr_rdata_uncompressed_wire(const nsd_type_descriptor_type *descriptor,
const struct rr *rr1, const uint8_t* rr2_rdata, uint16_t rr2_rdlen)
{
size_t i;
uint16_t offset1 = 0, offset2 = 0;
int res;
if(!descriptor->has_references) {
res = compare_bytestring(rr1->rdata, rr1->rdlength,
rr2_rdata, rr2_rdlen);
if(res != 0)
return 0;
return 1;
}
for(i=0; i < descriptor->rdata.length; i++) {
uint16_t field_len1, field_len2;
struct domain* domain1, *domain2;
int malf1 = 0, malf2 = 0;
if((rr1->rdlength == offset1 || rr2_rdlen == offset2) &&
descriptor->rdata.fields[i].is_optional) {
int remain1 = rr1->rdlength - offset1;
int remain2 = rr2_rdlen - offset2;
if(remain1 < remain2)
return 0;
if(remain1 > remain2)
return 0;
return 1;
}
if(!lookup_rdata_field_entry(descriptor, i, rr1, offset1,
&field_len1, &domain1))
malf1 = 1;
if(!lookup_rdata_field_entry_uncompressed_wire(descriptor, i,
rr2_rdata, rr2_rdlen, offset2, &field_len2, &domain2))
malf2 = 1;
if(malf1 || malf2) {
if(!malf1 && malf2)
return 0;
if(malf1 && !malf2)
return 0;
return 1;
}
if(domain1) {
if(domain2) {
res = dname_compare(domain_dname(domain1),
domain_dname(domain2));
if(res != 0)
return 0;
} else {
uint16_t dname_len2 = buf_dname_length(
rr2_rdata+offset2,
rr2_rdlen-offset2);
if(domain_dname(domain1)->name_size !=
dname_len2) {
return 0;
}
if(!dname_equal_nocase(
(uint8_t*)dname_name(domain_dname(
domain1)),
(uint8_t*)rr2_rdata+offset2,
dname_len2)) {
return 0;
}
}
} else {
if(domain2) {
uint16_t dname_len1 = buf_dname_length(
rr1->rdata + offset1,
rr1->rdlength-offset1);
if(dname_len1 !=
domain_dname(domain2)->name_size) {
return 0;
}
if(!dname_equal_nocase(
(uint8_t*)rr1->rdata+offset1,
(uint8_t*)dname_name(domain_dname(
domain2)),
dname_len1)) {
return 0;
}
} else {
res = compare_bytestring(rr1->rdata + offset1,
field_len1, rr2_rdata + offset2,
field_len2);
if(res != 0)
return 0;
}
}
offset1 += field_len1;
offset2 += field_len2;
}
return 1;
}
struct domain*
retrieve_rdata_ref_domain_offset(const struct rr* rr, uint16_t offset)
{
struct domain *domain;
if(rr->rdlength < offset+sizeof(void*))
return NULL;
memcpy(&domain, rr->rdata+offset, sizeof(void*));
return domain;
}
struct domain*
retrieve_rdata_ref_domain(const struct rr* rr)
{
struct domain *domain;
if(rr->rdlength < sizeof(void*))
return NULL;
memcpy(&domain, rr->rdata, sizeof(void*));
return domain;
}
struct domain*
retrieve_ns_ref_domain(const struct rr* rr)
{
assert(rr->type == TYPE_NS);
return retrieve_rdata_ref_domain(rr);
}
struct domain*
retrieve_cname_ref_domain(const struct rr* rr)
{
assert(rr->type == TYPE_CNAME);
return retrieve_rdata_ref_domain(rr);
}
struct domain*
retrieve_dname_ref_domain(const struct rr* rr)
{
assert(rr->type == TYPE_DNAME);
return retrieve_rdata_ref_domain(rr);
}
struct domain*
retrieve_mb_ref_domain(const struct rr* rr)
{
assert(rr->type == TYPE_MB);
return retrieve_rdata_ref_domain(rr);
}
struct domain*
retrieve_mx_ref_domain(const struct rr* rr)
{
assert(rr->type == TYPE_MX);
return retrieve_rdata_ref_domain_offset(rr, 2);
}
struct domain*
retrieve_kx_ref_domain(const struct rr* rr)
{
assert(rr->type == TYPE_KX);
return retrieve_rdata_ref_domain_offset(rr, 2);
}
struct domain*
retrieve_rt_ref_domain(const struct rr* rr)
{
assert(rr->type == TYPE_RT);
return retrieve_rdata_ref_domain_offset(rr, 2);
}
struct domain*
retrieve_srv_ref_domain(const struct rr* rr)
{
assert(rr->type == TYPE_SRV);
return retrieve_rdata_ref_domain_offset(rr, 6);
}
struct domain*
retrieve_ptr_ref_domain(const struct rr* rr)
{
assert(rr->type == TYPE_PTR);
return retrieve_rdata_ref_domain(rr);
}
int
retrieve_soa_rdata_serial(const struct rr* rr, uint32_t* serial)
{
assert(rr->type == TYPE_SOA);
if(rr->rdlength < 20 + 2*sizeof(void*))
return 0;
*serial = read_uint32(rr->rdata+2*sizeof(void*));
return 1;
}
int
retrieve_soa_rdata_minttl(const struct rr* rr, uint32_t* minttl)
{
assert(rr->type == TYPE_SOA);
if(rr->rdlength < 20 + 2*sizeof(void*))
return 0;
*minttl = read_uint32(rr->rdata+2*sizeof(void*)+16);
return 1;
}
struct dname* retrieve_cname_ref_dname(const struct rr* rr)
{
struct domain* domain;
assert(rr->type == TYPE_CNAME);
domain = retrieve_rdata_ref_domain(rr);
if(!domain)
return NULL;
return domain_dname(domain);
}
void
rr_lower_usage(namedb_type* db, rr_type* rr)
{
const nsd_type_descriptor_type *descriptor =
nsd_type_descriptor(rr->type);
uint16_t offset = 0;
size_t i;
for(i=0; i<descriptor->rdata.length; i++) {
uint16_t field_len;
struct domain* domain;
if(rr->rdlength == offset &&
descriptor->rdata.fields[i].is_optional)
break;
if(!lookup_rdata_field_entry(descriptor, i, rr, offset,
&field_len, &domain))
break;
if(domain) {
assert(domain->usage > 0);
domain->usage --;
if(domain->usage == 0)
domain_table_deldomain(db,
domain);
}
offset += field_len;
}
}
const char*
read_rdata_fail_str(int32_t code)
{
switch(code) {
case TRUNCATED:
return "out of memory";
case MALFORMED:
return "malformed rdata fields";
default:
break;
}
return "failed to read rdata fields";
}