rrset.c 5.95 KB
Newer Older
1
/*  Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
Lubos Slovak's avatar
Lubos Slovak committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

17
#include <assert.h>
18 19
#include <stdbool.h>
#include <stdint.h>
20

21
#include "libknot/attribute.h"
22
#include "libknot/consts.h"
23
#include "libknot/descriptor.h"
24
#include "libknot/dname.h"
25
#include "libknot/errcode.h"
Jan Včelák's avatar
Jan Včelák committed
26 27
#include "libknot/rrset.h"
#include "libknot/rrtype/naptr.h"
28
#include "libknot/rrtype/rrsig.h"
29
#include "contrib/mempattern.h"
30

31
_public_
32
knot_rrset_t *knot_rrset_new(const knot_dname_t *owner, uint16_t type,
33
                             uint16_t rclass, uint32_t ttl, knot_mm_t *mm)
34
{
35 36 37 38 39
	knot_dname_t *owner_cpy = knot_dname_copy(owner, mm);
	if (owner_cpy == NULL) {
		return NULL;
	}

40
	knot_rrset_t *ret = mm_alloc(mm, sizeof(knot_rrset_t));
41
	if (ret == NULL) {
42
		knot_dname_free(&owner_cpy, mm);
43 44 45
		return NULL;
	}

46
	knot_rrset_init(ret, owner_cpy, type, rclass, ttl);
47 48 49 50

	return ret;
}

51
_public_
52
void knot_rrset_init(knot_rrset_t *rrset, knot_dname_t *owner, uint16_t type,
53
                     uint16_t rclass, uint32_t ttl)
54
{
55 56 57
	rrset->owner = owner;
	rrset->type = type;
	rrset->rclass = rclass;
58
	rrset->ttl = ttl;
59
	knot_rdataset_init(&rrset->rrs);
60
	rrset->additional = NULL;
61 62
}

63
_public_
64
void knot_rrset_init_empty(knot_rrset_t *rrset)
65
{
66
	knot_rrset_init(rrset, NULL, 0, KNOT_CLASS_IN, 0);
67 68
}

69
_public_
70
knot_rrset_t *knot_rrset_copy(const knot_rrset_t *src, knot_mm_t *mm)
71 72
{
	if (src == NULL) {
73
		return NULL;
74
	}
75

76
	knot_rrset_t *rrset = knot_rrset_new(src->owner, src->type,
77
	                                     src->rclass, src->ttl, mm);
78 79 80
	if (rrset == NULL) {
		return NULL;
	}
81

82
	int ret = knot_rdataset_copy(&rrset->rrs, &src->rrs, mm);
83 84 85 86
	if (ret != KNOT_EOK) {
		knot_rrset_free(&rrset, mm);
		return NULL;
	}
87

88
	return rrset;
89 90
}

91
_public_
92
void knot_rrset_free(knot_rrset_t **rrset, knot_mm_t *mm)
93
{
94 95
	if (rrset == NULL || *rrset == NULL) {
		return;
96
	}
Jan Včelák's avatar
Jan Včelák committed
97

98
	knot_rrset_clear(*rrset, mm);
99

100
	mm_free(mm, *rrset);
101 102 103
	*rrset = NULL;
}

104
_public_
105
void knot_rrset_clear(knot_rrset_t *rrset, knot_mm_t *mm)
106 107
{
	if (rrset) {
108
		knot_rdataset_clear(&rrset->rrs, mm);
109 110 111 112
		knot_dname_free(&rrset->owner, mm);
	}
}

113
_public_
114 115
int knot_rrset_add_rdata(knot_rrset_t *rrset, const uint8_t *data, uint16_t len,
                         knot_mm_t *mm)
116
{
117
	if (rrset == NULL || (data == NULL && len > 0)) {
118 119 120
		return KNOT_EINVAL;
	}

121 122 123
	uint8_t buf[knot_rdata_size(len)];
	knot_rdata_t *rdata = (knot_rdata_t *)buf;
	knot_rdata_init(rdata, len, data);
124

125
	return knot_rdataset_add(&rrset->rrs, rdata, mm);
126 127
}

128
_public_
129 130 131
bool knot_rrset_equal(const knot_rrset_t *r1,
                      const knot_rrset_t *r2,
                      knot_rrset_compare_type_t cmp)
132 133 134 135 136
{
	if (cmp == KNOT_RRSET_COMPARE_PTR) {
		return r1 == r2;
	}

137
	if (r1->type != r2->type) {
138
		return false;
139
	}
Jan Včelák's avatar
Jan Včelák committed
140

141 142 143 144
	if (r1->owner && r2->owner) {
		if (!knot_dname_is_equal(r1->owner, r2->owner)) {
			return false;
		}
145 146
	} else if (r1->owner != r2->owner) { // At least one is NULL.
		return false;
147
	}
148

149
	if (cmp == KNOT_RRSET_COMPARE_WHOLE) {
150
		return knot_rdataset_eq(&r1->rrs, &r2->rrs);
151
	}
152

153
	return true;
154
}
155

156
_public_
157 158
bool knot_rrset_empty(const knot_rrset_t *rrset)
{
159 160 161 162 163 164
	if (rrset) {
		uint16_t rr_count = rrset->rrs.rr_count;
		return rr_count == 0;
	} else {
		return true;
	}
165 166
}

167 168 169 170 171 172 173 174 175 176 177 178 179
_public_
bool knot_rrset_is_nsec3rel(const knot_rrset_t *rr)
{
	if (rr == NULL) {
		return false;
	}

	/* Is NSEC3 or non-empty RRSIG covering NSEC3. */
	return ((rr->type == KNOT_RRTYPE_NSEC3) ||
	        (rr->type == KNOT_RRTYPE_RRSIG
	         && knot_rrsig_type_covered(&rr->rrs, 0) == KNOT_RRTYPE_NSEC3));
}

180
_public_
181 182
int knot_rrset_rr_to_canonical(knot_rrset_t *rrset)
{
Jan Kadlec's avatar
Jan Kadlec committed
183
	if (rrset == NULL || rrset->rrs.rr_count != 1) {
184 185 186 187 188 189 190 191 192 193
		return KNOT_EINVAL;
	}

	/* Convert owner for all RRSets. */
	int ret = knot_dname_to_lower(rrset->owner);
	if (ret != KNOT_EOK) {
		return ret;
	}

	/* Convert DNAMEs in RDATA only for RFC4034 types. */
194 195 196 197
	if (!knot_rrtype_should_be_lowercased(rrset->type)) {
		return KNOT_EOK;
	}

198
	const knot_rdata_descriptor_t *desc = knot_get_rdata_descriptor(rrset->type);
199 200 201
	if (desc->type_name == NULL) {
		desc = knot_get_obsolete_rdata_descriptor(rrset->type);
	}
202

203
	knot_rdata_t *rdata = knot_rdataset_at(&rrset->rrs, 0);
Jan Kadlec's avatar
Jan Kadlec committed
204
	assert(rdata);
205 206
	uint16_t rdlen = rdata->len;
	uint8_t *pos = rdata->data;
207
	uint8_t *endpos = pos + rdlen;
208

209
	/* No RDATA */
Jan Kadlec's avatar
Jan Kadlec committed
210
	if (rdlen == 0) {
211 212
		return KNOT_EOK;
	}
213

214 215 216 217 218 219 220 221 222 223
	/* Otherwise, whole and not malformed RDATA are expected. */
	for (int i = 0; desc->block_types[i] != KNOT_RDATA_WF_END; ++i) {
		int type = desc->block_types[i];
		switch (type) {
		case KNOT_RDATA_WF_COMPRESSIBLE_DNAME:
		case KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME:
		case KNOT_RDATA_WF_FIXED_DNAME:
			ret = knot_dname_to_lower(pos);
			if (ret != KNOT_EOK) {
				return ret;
224
			}
225 226 227
			ret = knot_dname_size(pos);

			pos += ret;
228 229
			break;
		case KNOT_RDATA_WF_NAPTR_HEADER:
230 231 232 233 234 235
			ret = knot_naptr_header_size(pos, endpos);
			if (ret < 0) {
				return ret;
			}

			pos += ret;
236 237 238 239 240 241 242
			break;
		case KNOT_RDATA_WF_REMAINDER:
			break;
		default:
			/* Fixed size block */
			assert(type > 0);
			pos += type;
243 244 245 246 247
		}
	}

	return KNOT_EOK;
}
248 249 250 251 252 253 254 255 256

_public_
size_t knot_rrset_size(const knot_rrset_t *rrset)
{
	if (rrset == NULL) {
		return 0;
	}

	uint16_t rr_count = rrset->rrs.rr_count;
257

258 259 260 261 262
	size_t total_size = knot_dname_size(rrset->owner) * rr_count;

	for (size_t i = 0; i < rr_count; ++i) {
		const knot_rdata_t *rr = knot_rdataset_at(&rrset->rrs, i);
		assert(rr);
263
		/* 10B = TYPE + CLASS + TTL + RDLENGTH */
264
		total_size += rr->len + 10;
265 266 267 268
	}

	return total_size;
}