summaryrefslogtreecommitdiffstats
path: root/lib/dns/soa.c
blob: ca5ca8858c9df9a56c6070d19046dc249655473a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/*
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
 *
 * SPDX-License-Identifier: MPL-2.0
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
 *
 * See the COPYRIGHT file distributed with this work for additional
 * information regarding copyright ownership.
 */

/*! \file */

#include <inttypes.h>
#include <string.h>

#include <isc/buffer.h>
#include <isc/util.h>

#include <dns/rdata.h>
#include <dns/rdatastruct.h>
#include <dns/soa.h>

static uint32_t
decode_uint32(unsigned char *p) {
	return (((uint32_t)p[0] << 24) + ((uint32_t)p[1] << 16) +
		((uint32_t)p[2] << 8) + ((uint32_t)p[3] << 0));
}

static void
encode_uint32(uint32_t val, unsigned char *p) {
	p[0] = (uint8_t)(val >> 24);
	p[1] = (uint8_t)(val >> 16);
	p[2] = (uint8_t)(val >> 8);
	p[3] = (uint8_t)(val >> 0);
}

static uint32_t
soa_get(dns_rdata_t *rdata, int offset) {
	INSIST(rdata->type == dns_rdatatype_soa);
	/*
	 * Locate the field within the SOA RDATA based
	 * on its position relative to the end of the data.
	 *
	 * This is a bit of a kludge, but the alternative approach of
	 * using dns_rdata_tostruct() and dns_rdata_fromstruct() would
	 * involve a lot of unnecessary work (like building domain
	 * names and allocating temporary memory) when all we really
	 * want to do is to get 32 bits of fixed-sized data.
	 */
	INSIST(rdata->length >= 20);
	INSIST(offset >= 0 && offset <= 16);
	return (decode_uint32(rdata->data + rdata->length - 20 + offset));
}

isc_result_t
dns_soa_buildrdata(const dns_name_t *origin, const dns_name_t *contact,
		   dns_rdataclass_t rdclass, uint32_t serial, uint32_t refresh,
		   uint32_t retry, uint32_t expire, uint32_t minimum,
		   unsigned char *buffer, dns_rdata_t *rdata) {
	dns_rdata_soa_t soa;
	isc_buffer_t rdatabuf;

	REQUIRE(origin != NULL);
	REQUIRE(contact != NULL);

	memset(buffer, 0, DNS_SOA_BUFFERSIZE);
	isc_buffer_init(&rdatabuf, buffer, DNS_SOA_BUFFERSIZE);

	soa.common.rdtype = dns_rdatatype_soa;
	soa.common.rdclass = rdclass;
	soa.mctx = NULL;
	soa.serial = serial;
	soa.refresh = refresh;
	soa.retry = retry;
	soa.expire = expire;
	soa.minimum = minimum;
	dns_name_init(&soa.origin, NULL);
	dns_name_clone(origin, &soa.origin);
	dns_name_init(&soa.contact, NULL);
	dns_name_clone(contact, &soa.contact);

	return (dns_rdata_fromstruct(rdata, rdclass, dns_rdatatype_soa, &soa,
				     &rdatabuf));
}

uint32_t
dns_soa_getserial(dns_rdata_t *rdata) {
	return (soa_get(rdata, 0));
}
uint32_t
dns_soa_getrefresh(dns_rdata_t *rdata) {
	return (soa_get(rdata, 4));
}
uint32_t
dns_soa_getretry(dns_rdata_t *rdata) {
	return (soa_get(rdata, 8));
}
uint32_t
dns_soa_getexpire(dns_rdata_t *rdata) {
	return (soa_get(rdata, 12));
}
uint32_t
dns_soa_getminimum(dns_rdata_t *rdata) {
	return (soa_get(rdata, 16));
}

static void
soa_set(dns_rdata_t *rdata, uint32_t val, int offset) {
	INSIST(rdata->type == dns_rdatatype_soa);
	INSIST(rdata->length >= 20);
	INSIST(offset >= 0 && offset <= 16);
	encode_uint32(val, rdata->data + rdata->length - 20 + offset);
}

void
dns_soa_setserial(uint32_t val, dns_rdata_t *rdata) {
	soa_set(rdata, val, 0);
}
void
dns_soa_setrefresh(uint32_t val, dns_rdata_t *rdata) {
	soa_set(rdata, val, 4);
}
void
dns_soa_setretry(uint32_t val, dns_rdata_t *rdata) {
	soa_set(rdata, val, 8);
}
void
dns_soa_setexpire(uint32_t val, dns_rdata_t *rdata) {
	soa_set(rdata, val, 12);
}
void
dns_soa_setminimum(uint32_t val, dns_rdata_t *rdata) {
	soa_set(rdata, val, 16);
}