Main Page
Related Pages
Data Structures
Files
File List
Globals
update.c
Go to the documentation of this file.
1
/* update.c
2
*
3
* Functions for RFC 2136 Dynamic Update
4
*
5
* Copyright (c) 2005-2008, NLnet Labs. All rights reserved.
6
*
7
* See LICENSE for the license.
8
*/
9
10
#include <
ldns/config.h
>
11
12
#include <
ldns/ldns.h
>
13
14
#include <strings.h>
15
#include <stdlib.h>
16
#include <limits.h>
17
18
/*
19
* RFC 2136 sections mapped to RFC 1035:
20
* zone/ZO -- QD/question
21
* prerequisites/PR -- AN/answers
22
* updates/UP -- NS/authority records
23
* additional data/AD -- AR/additional records
24
*/
25
26
ldns_pkt
*
27
ldns_update_pkt_new
(
ldns_rdf
*zone_rdf,
ldns_rr_class
c,
28
ldns_rr_list
*pr_rrlist,
ldns_rr_list
*up_rrlist,
ldns_rr_list
*ad_rrlist)
29
{
30
ldns_pkt
*p;
31
32
if
(!zone_rdf || !up_rrlist) {
33
return
NULL;
34
}
35
36
if
(c == 0) {
37
c =
LDNS_RR_CLASS_IN
;
38
}
39
40
/* Create packet, fill in Zone Section. */
41
p =
ldns_pkt_query_new
(zone_rdf,
LDNS_RR_TYPE_SOA
, c,
LDNS_RD
);
42
if
(!p) {
43
return
NULL;
44
}
45
zone_rdf = NULL;
/* No longer safe to use. */
46
47
ldns_pkt_set_opcode
(p,
LDNS_PACKET_UPDATE
);
48
49
ldns_rr_list_deep_free
(p->
_authority
);
50
51
ldns_pkt_set_authority
(p,
ldns_rr_list_clone
(up_rrlist));
52
53
ldns_update_set_upcount
(p,
ldns_rr_list_rr_count
(up_rrlist));
54
55
if
(pr_rrlist) {
56
ldns_rr_list_deep_free
(p->
_answer
);
/*XXX access function */
57
ldns_pkt_set_answer
(p,
ldns_rr_list_clone
(pr_rrlist));
58
ldns_update_set_prcount
(p,
ldns_rr_list_rr_count
(pr_rrlist));
59
}
60
61
if
(ad_rrlist) {
62
ldns_rr_list_deep_free
(p->
_additional
);
63
ldns_pkt_set_additional
(p,
ldns_rr_list_clone
(ad_rrlist));
64
ldns_update_set_adcount
(p,
ldns_rr_list_rr_count
(ad_rrlist));
65
}
66
return
p;
67
}
68
69
ldns_status
70
ldns_update_pkt_tsig_add
(
ldns_pkt
*p,
ldns_resolver
*r)
71
{
72
#ifdef HAVE_SSL
73
uint16_t fudge = 300;
/* Recommended fudge. [RFC2845 6.4] */
74
if
(
ldns_resolver_tsig_keyname
(r) &&
ldns_resolver_tsig_keydata
(r))
75
return
ldns_pkt_tsig_sign
(p,
ldns_resolver_tsig_keyname
(r),
76
ldns_resolver_tsig_keydata
(r), fudge,
77
ldns_resolver_tsig_algorithm
(r), NULL);
78
#else
79
/* do nothing */
80
(void)p;
81
(void)r;
82
#endif
/* HAVE_SSL */
83
/* No TSIG to do. */
84
return
LDNS_STATUS_OK
;
85
}
86
87
/* Move to higher.c or similar? */
88
/* XXX doc */
89
ldns_status
90
ldns_update_soa_mname
(
ldns_rdf
*zone,
ldns_resolver
*r,
91
ldns_rr_class
c,
ldns_rdf
**mname)
92
{
93
ldns_rr
*soa_rr;
94
ldns_pkt
*query, *resp;
95
96
/* Nondestructive, so clone 'zone' here */
97
query =
ldns_pkt_query_new
(
ldns_rdf_clone
(zone),
LDNS_RR_TYPE_SOA
,
98
c,
LDNS_RD
);
99
if
(!query) {
100
return
LDNS_STATUS_ERR
;
101
}
102
103
ldns_pkt_set_random_id
(query);
104
if
(
ldns_resolver_send_pkt
(&resp, r, query) !=
LDNS_STATUS_OK
) {
105
ldns_pkt_free
(query);
106
return
LDNS_STATUS_ERR
;
107
}
108
ldns_pkt_free
(query);
109
if
(!resp) {
110
return
LDNS_STATUS_ERR
;
111
}
112
113
/* Expect a SOA answer. */
114
*mname = NULL;
115
while
((soa_rr =
ldns_rr_list_pop_rr
(
ldns_pkt_answer
(resp)))) {
116
if
(
ldns_rr_get_type
(soa_rr) !=
LDNS_RR_TYPE_SOA
117
||
ldns_rr_rdf
(soa_rr, 0) == NULL)
118
continue
;
119
/* [RFC1035 3.3.13] */
120
*mname =
ldns_rdf_clone
(
ldns_rr_rdf
(soa_rr, 0));
121
break
;
122
}
123
ldns_pkt_free
(resp);
124
125
return
*mname ?
LDNS_STATUS_OK
:
LDNS_STATUS_ERR
;
126
}
127
128
/* Try to get zone and MNAME from SOA queries. */
129
ldns_status
130
ldns_update_soa_zone_mname
(
const
char
*fqdn,
ldns_resolver
*r,
131
ldns_rr_class
c,
ldns_rdf
**zone_rdf,
ldns_rdf
**mname_rdf)
132
{
133
ldns_rr
*soa_rr, *rr;
134
ldns_rdf
*soa_zone = NULL, *soa_mname = NULL;
135
ldns_rdf
*ipaddr, *fqdn_rdf, *tmp;
136
ldns_rdf
**nslist;
137
ldns_pkt
*query, *resp;
138
size_t
i;
139
140
/*
141
* XXX Ok, this cannot be the best way to find this...?
142
* XXX (I run into weird cache-related stuff here)
143
*/
144
145
/* Step 1 - first find a nameserver that should know *something* */
146
fqdn_rdf =
ldns_dname_new_frm_str
(fqdn);
147
query =
ldns_pkt_query_new
(fqdn_rdf,
LDNS_RR_TYPE_SOA
, c,
LDNS_RD
);
148
if
(!query) {
149
return
LDNS_STATUS_ERR
;
150
}
151
fqdn_rdf = NULL;
152
153
ldns_pkt_set_random_id
(query);
154
if
(
ldns_resolver_send_pkt
(&resp, r, query) !=
LDNS_STATUS_OK
) {
155
ldns_pkt_free
(query);
156
return
LDNS_STATUS_ERR
;
157
}
158
ldns_pkt_free
(query);
159
if
(!resp) {
160
return
LDNS_STATUS_ERR
;
161
}
162
163
/* XXX Is it safe to only look in authority section here? */
164
while
((soa_rr =
ldns_rr_list_pop_rr
(
ldns_pkt_authority
(resp)))) {
165
if
(
ldns_rr_get_type
(soa_rr) !=
LDNS_RR_TYPE_SOA
166
||
ldns_rr_rdf
(soa_rr, 0) == NULL)
167
continue
;
168
/* [RFC1035 3.3.13] */
169
soa_mname =
ldns_rdf_clone
(
ldns_rr_rdf
(soa_rr, 0));
170
break
;
171
}
172
ldns_pkt_free
(resp);
173
if
(!soa_rr) {
174
return
LDNS_STATUS_ERR
;
175
}
176
177
/* Step 2 - find SOA MNAME IP address, add to resolver */
178
query =
ldns_pkt_query_new
(soa_mname,
LDNS_RR_TYPE_A
, c,
LDNS_RD
);
179
if
(!query) {
180
return
LDNS_STATUS_ERR
;
181
}
182
soa_mname = NULL;
183
184
ldns_pkt_set_random_id
(query);
185
if
(
ldns_resolver_send_pkt
(&resp, r, query) !=
LDNS_STATUS_OK
) {
186
ldns_pkt_free
(query);
187
return
LDNS_STATUS_ERR
;
188
}
189
ldns_pkt_free
(query);
190
if
(!resp) {
191
return
LDNS_STATUS_ERR
;
192
}
193
194
if
(
ldns_pkt_ancount
(resp) == 0) {
195
ldns_pkt_free
(resp);
196
return
LDNS_STATUS_ERR
;
197
}
198
199
/* XXX There may be more than one answer RR here. */
200
rr =
ldns_rr_list_pop_rr
(
ldns_pkt_answer
(resp));
201
ipaddr =
ldns_rr_rdf
(rr, 0);
202
203
/* Put the SOA mname IP first in the nameserver list. */
204
nslist =
ldns_resolver_nameservers
(r);
205
for
(i = 0; i <
ldns_resolver_nameserver_count
(r); i++) {
206
if
(
ldns_rdf_compare
(ipaddr, nslist[i]) == 0) {
207
if
(i) {
208
tmp = nslist[0];
209
nslist[0] = nslist[i];
210
nslist[i] = tmp;
211
}
212
break
;
213
}
214
}
215
if
(i >=
ldns_resolver_nameserver_count
(r)) {
216
/* SOA mname was not part of the resolver so add it first. */
217
(void)
ldns_resolver_push_nameserver
(r, ipaddr);
218
nslist =
ldns_resolver_nameservers
(r);
219
i =
ldns_resolver_nameserver_count
(r) - 1;
220
tmp = nslist[0];
221
nslist[0] = nslist[i];
222
nslist[i] = tmp;
223
}
224
ldns_pkt_free
(resp);
225
226
/* Make sure to ask the first in the list, i.e SOA mname */
227
ldns_resolver_set_random
(r,
false
);
228
229
/* Step 3 - Redo SOA query, sending to SOA MNAME directly. */
230
fqdn_rdf =
ldns_dname_new_frm_str
(fqdn);
231
query =
ldns_pkt_query_new
(fqdn_rdf,
LDNS_RR_TYPE_SOA
, c,
LDNS_RD
);
232
if
(!query) {
233
return
LDNS_STATUS_ERR
;
234
}
235
fqdn_rdf = NULL;
236
237
ldns_pkt_set_random_id
(query);
238
if
(
ldns_resolver_send_pkt
(&resp, r, query) !=
LDNS_STATUS_OK
) {
239
ldns_pkt_free
(query);
240
return
LDNS_STATUS_ERR
;
241
}
242
ldns_pkt_free
(query);
243
if
(!resp) {
244
return
LDNS_STATUS_ERR
;
245
}
246
247
/* XXX Is it safe to only look in authority section here, too? */
248
while
((soa_rr =
ldns_rr_list_pop_rr
(
ldns_pkt_authority
(resp)))) {
249
if
(
ldns_rr_get_type
(soa_rr) !=
LDNS_RR_TYPE_SOA
250
||
ldns_rr_rdf
(soa_rr, 0) == NULL)
251
continue
;
252
/* [RFC1035 3.3.13] */
253
soa_mname =
ldns_rdf_clone
(
ldns_rr_rdf
(soa_rr, 0));
254
soa_zone =
ldns_rdf_clone
(
ldns_rr_owner
(soa_rr));
255
break
;
256
}
257
ldns_pkt_free
(resp);
258
if
(!soa_rr) {
259
return
LDNS_STATUS_ERR
;
260
}
261
262
/* That seems to have worked, pass results to caller. */
263
*zone_rdf = soa_zone;
264
*mname_rdf = soa_mname;
265
return
LDNS_STATUS_OK
;
266
}
267
268
/*
269
* ldns_update_{get,set}_{zo,pr,up,ad}count
270
*/
271
272
uint16_t
273
ldns_update_zocount
(
const
ldns_pkt
*p)
274
{
275
return
ldns_pkt_qdcount
(p);
276
}
277
278
uint16_t
279
ldns_update_prcount
(
const
ldns_pkt
*p)
280
{
281
return
ldns_pkt_ancount
(p);
282
}
283
284
uint16_t
285
ldns_update_upcount
(
const
ldns_pkt
*p)
286
{
287
return
ldns_pkt_nscount
(p);
288
}
289
290
uint16_t
291
ldns_update_ad
(
const
ldns_pkt
*p)
292
{
293
return
ldns_pkt_arcount
(p);
294
}
295
296
void
297
ldns_update_set_zo
(
ldns_pkt
*p, uint16_t v)
298
{
299
ldns_pkt_set_qdcount
(p, v);
300
}
301
302
void
303
ldns_update_set_prcount
(
ldns_pkt
*p, uint16_t v)
304
{
305
ldns_pkt_set_ancount
(p, v);
306
}
307
308
void
309
ldns_update_set_upcount
(
ldns_pkt
*p, uint16_t v)
310
{
311
ldns_pkt_set_nscount
(p, v);
312
}
313
314
void
315
ldns_update_set_adcount
(
ldns_pkt
*p, uint16_t v)
316
{
317
ldns_pkt_set_arcount
(p, v);
318
}
Generated on Sat Nov 24 2012 11:34:21 for ldns by
1.8.1.2