]>
Commit | Line | Data |
---|---|---|
b992d7e2 DN |
1 | /* ddns.c |
2 | ||
3 | Dynamic DNS updates. */ | |
4 | ||
5 | /* | |
385fcb27 | 6 | * Copyright (c) 2000-2001 Internet Software Consortium. |
b992d7e2 DN |
7 | * All rights reserved. |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * | |
13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | |
18 | * 3. Neither the name of The Internet Software Consortium nor the names | |
19 | * of its contributors may be used to endorse or promote products derived | |
20 | * from this software without specific prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND | |
23 | * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
24 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
25 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
26 | * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR | |
27 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
28 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
29 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
30 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
31 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
32 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
33 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
34 | * SUCH DAMAGE. | |
35 | * | |
0598e123 TL |
36 | * This software has been donated to the Internet Software Consortium |
37 | * by Damien Neil of Nominum, Inc. | |
38 | * | |
b992d7e2 | 39 | * To learn more about the Internet Software Consortium, see |
0598e123 | 40 | * ``http://www.isc.org/''. To learn more about Nominum, Inc., see |
b992d7e2 DN |
41 | * ``http://www.nominum.com''. |
42 | */ | |
43 | ||
44 | #ifndef lint | |
45 | static char copyright[] = | |
e9d45f83 | 46 | "$Id: ddns.c,v 1.11 2001/01/19 10:59:10 mellon Exp $ Copyright (c) 2000-2001 The Internet Software Consortium. All rights reserved.\n"; |
b992d7e2 DN |
47 | #endif /* not lint */ |
48 | ||
49 | #include "dhcpd.h" | |
ec64b462 TL |
50 | #include "minires/md5.h" |
51 | #include "minires/minires.h" | |
b992d7e2 DN |
52 | |
53 | #ifdef NSUPDATE | |
54 | ||
55 | /* Have to use TXT records for now. */ | |
56 | #define T_DHCID T_TXT | |
57 | ||
0598e123 TL |
58 | /* DN: No way of checking that there is enough space in a data_string's |
59 | buffer. Be certain to allocate enough! | |
385fcb27 | 60 | TL: This is why the expression evaluation code allocates a *new* |
0598e123 | 61 | data_string. :') */ |
b992d7e2 DN |
62 | static void data_string_append (struct data_string *ds1, |
63 | struct data_string *ds2) | |
64 | { | |
65 | memcpy (ds1 -> buffer -> data + ds1 -> len, | |
66 | ds2 -> data, | |
67 | ds2 -> len); | |
68 | ds1 -> len += ds2 -> len; | |
69 | } | |
70 | ||
ec64b462 TL |
71 | static isc_result_t ddns_update_a (struct data_string *ddns_fwd_name, |
72 | struct iaddr ddns_addr, | |
73 | struct data_string *ddns_dhcid, | |
74 | unsigned long ttl) | |
b992d7e2 | 75 | { |
385fcb27 | 76 | ns_updque updqueue; |
b992d7e2 | 77 | ns_updrec *updrec; |
ec64b462 | 78 | isc_result_t result; |
bdad826f TL |
79 | char ddns_address [16]; |
80 | ||
81 | if (ddns_addr.len != 4) | |
ec64b462 | 82 | return ISC_R_INVALIDARG; |
bdad826f TL |
83 | #ifndef NO_SNPRINTF |
84 | snprintf (ddns_address, 16, "%d.%d.%d.%d", | |
85 | ddns_addr.iabuf[0], ddns_addr.iabuf[1], | |
86 | ddns_addr.iabuf[2], ddns_addr.iabuf[3]); | |
87 | #else | |
88 | sprintf (ddns_address, "%d.%d.%d.%d", | |
89 | ddns_addr.iabuf[0], ddns_addr.iabuf[1], | |
90 | ddns_addr.iabuf[2], ddns_addr.iabuf[3]); | |
91 | #endif | |
b992d7e2 DN |
92 | |
93 | /* | |
94 | * When a DHCP client or server intends to update an A RR, it first | |
95 | * prepares a DNS UPDATE query which includes as a prerequisite the | |
96 | * assertion that the name does not exist. The update section of the | |
97 | * query attempts to add the new name and its IP address mapping (an A | |
98 | * RR), and the DHCID RR with its unique client-identity. | |
99 | * -- "Interaction between DHCP and DNS" | |
100 | */ | |
101 | ||
385fcb27 | 102 | ISC_LIST_INIT (updqueue); |
b992d7e2 DN |
103 | |
104 | /* | |
105 | * A RR does not exist. | |
106 | */ | |
478028e7 TL |
107 | updrec = minires_mkupdrec (S_PREREQ, |
108 | (const char *)ddns_fwd_name -> data, | |
b992d7e2 | 109 | C_IN, T_A, 0); |
ec64b462 TL |
110 | if (!updrec) { |
111 | result = ISC_R_NOMEMORY; | |
112 | goto error; | |
113 | } | |
b992d7e2 | 114 | |
478028e7 TL |
115 | updrec -> r_data = (unsigned char *)0; |
116 | updrec -> r_size = 0; | |
b992d7e2 DN |
117 | updrec -> r_opcode = NXDOMAIN; |
118 | ||
385fcb27 | 119 | ISC_LIST_APPEND (updqueue, updrec, r_link); |
b992d7e2 DN |
120 | |
121 | ||
122 | /* | |
123 | * Add A RR. | |
124 | */ | |
478028e7 TL |
125 | updrec = minires_mkupdrec (S_UPDATE, |
126 | (const char *)ddns_fwd_name -> data, | |
b992d7e2 | 127 | C_IN, T_A, ttl); |
ec64b462 TL |
128 | if (!updrec) { |
129 | result = ISC_R_NOMEMORY; | |
130 | goto error; | |
131 | } | |
b992d7e2 | 132 | |
478028e7 | 133 | updrec -> r_data = (unsigned char *)ddns_address; |
bdad826f | 134 | updrec -> r_size = strlen (ddns_address); |
b992d7e2 DN |
135 | updrec -> r_opcode = ADD; |
136 | ||
385fcb27 | 137 | ISC_LIST_APPEND (updqueue, updrec, r_link); |
b992d7e2 DN |
138 | |
139 | ||
140 | /* | |
141 | * Add DHCID RR. | |
142 | */ | |
478028e7 TL |
143 | updrec = minires_mkupdrec (S_UPDATE, |
144 | (const char *)ddns_fwd_name -> data, | |
b992d7e2 | 145 | C_IN, T_DHCID, ttl); |
ec64b462 TL |
146 | if (!updrec) { |
147 | result = ISC_R_NOMEMORY; | |
148 | goto error; | |
149 | } | |
b992d7e2 | 150 | |
ee83afae | 151 | updrec -> r_data = ddns_dhcid -> data; |
b992d7e2 DN |
152 | updrec -> r_size = ddns_dhcid -> len; |
153 | updrec -> r_opcode = ADD; | |
154 | ||
385fcb27 | 155 | ISC_LIST_APPEND (updqueue, updrec, r_link); |
b992d7e2 DN |
156 | |
157 | ||
158 | /* | |
159 | * Attempt to perform the update. | |
160 | */ | |
385fcb27 TL |
161 | result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue)); |
162 | ||
163 | print_dns_status ((int)result, &updqueue); | |
b992d7e2 | 164 | |
385fcb27 TL |
165 | while (!ISC_LIST_EMPTY (updqueue)) { |
166 | updrec = ISC_LIST_HEAD (updqueue); | |
167 | ISC_LIST_UNLINK (updqueue, updrec, r_link); | |
b992d7e2 DN |
168 | minires_freeupdrec (updrec); |
169 | } | |
170 | ||
171 | ||
172 | /* | |
173 | * If this update operation succeeds, the updater can conclude that it | |
174 | * has added a new name whose only RRs are the A and DHCID RR records. | |
175 | * The A RR update is now complete (and a client updater is finished, | |
176 | * while a server might proceed to perform a PTR RR update). | |
177 | * -- "Interaction between DHCP and DNS" | |
178 | */ | |
179 | ||
ec64b462 | 180 | if (result == ISC_R_SUCCESS) |
b992d7e2 DN |
181 | return result; |
182 | ||
183 | ||
184 | /* | |
185 | * If the first update operation fails with YXDOMAIN, the updater can | |
186 | * conclude that the intended name is in use. The updater then | |
187 | * attempts to confirm that the DNS name is not being used by some | |
188 | * other host. The updater prepares a second UPDATE query in which the | |
189 | * prerequisite is that the desired name has attached to it a DHCID RR | |
190 | * whose contents match the client identity. The update section of | |
191 | * this query deletes the existing A records on the name, and adds the | |
192 | * A record that matches the DHCP binding and the DHCID RR with the | |
193 | * client identity. | |
194 | * -- "Interaction between DHCP and DNS" | |
195 | */ | |
196 | ||
ec64b462 | 197 | if (result != ISC_R_YXDOMAIN) |
b992d7e2 DN |
198 | return result; |
199 | ||
200 | ||
201 | /* | |
202 | * DHCID RR exists, and matches client identity. | |
203 | */ | |
478028e7 TL |
204 | updrec = minires_mkupdrec (S_PREREQ, |
205 | (const char *)ddns_fwd_name -> data, | |
b992d7e2 | 206 | C_IN, T_DHCID, 0); |
ec64b462 TL |
207 | if (!updrec) { |
208 | result = ISC_R_NOMEMORY; | |
209 | goto error; | |
210 | } | |
b992d7e2 | 211 | |
ee83afae | 212 | updrec -> r_data = ddns_dhcid -> data; |
b992d7e2 DN |
213 | updrec -> r_size = ddns_dhcid -> len; |
214 | updrec -> r_opcode = YXRRSET; | |
215 | ||
385fcb27 | 216 | ISC_LIST_APPEND (updqueue, updrec, r_link); |
b992d7e2 DN |
217 | |
218 | ||
219 | /* | |
220 | * Delete A RRset. | |
221 | */ | |
478028e7 TL |
222 | updrec = minires_mkupdrec (S_UPDATE, |
223 | (const char *)ddns_fwd_name -> data, | |
b992d7e2 | 224 | C_IN, T_A, 0); |
ec64b462 TL |
225 | if (!updrec) { |
226 | result = ISC_R_NOMEMORY; | |
227 | goto error; | |
228 | } | |
b992d7e2 DN |
229 | |
230 | updrec -> r_data = (unsigned char *)0; | |
231 | updrec -> r_size = 0; | |
232 | updrec -> r_opcode = DELETE; | |
233 | ||
385fcb27 | 234 | ISC_LIST_APPEND (updqueue, updrec, r_link); |
b992d7e2 DN |
235 | |
236 | ||
237 | /* | |
238 | * Add A RR. | |
239 | */ | |
478028e7 TL |
240 | updrec = minires_mkupdrec (S_UPDATE, |
241 | (const char *)ddns_fwd_name -> data, | |
b992d7e2 | 242 | C_IN, T_A, ttl); |
ec64b462 TL |
243 | if (!updrec) { |
244 | result = ISC_R_NOMEMORY; | |
245 | goto error; | |
246 | } | |
b992d7e2 | 247 | |
478028e7 | 248 | updrec -> r_data = (unsigned char *)ddns_address; |
bdad826f | 249 | updrec -> r_size = strlen (ddns_address); |
b992d7e2 DN |
250 | updrec -> r_opcode = ADD; |
251 | ||
385fcb27 | 252 | ISC_LIST_APPEND (updqueue, updrec, r_link); |
b992d7e2 DN |
253 | |
254 | ||
255 | /* | |
256 | * Attempt to perform the update. | |
257 | */ | |
385fcb27 TL |
258 | result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue)); |
259 | ||
260 | print_dns_status ((int)result, &updqueue); | |
b992d7e2 | 261 | |
385fcb27 TL |
262 | while (!ISC_LIST_EMPTY (updqueue)) { |
263 | updrec = ISC_LIST_HEAD (updqueue); | |
264 | ISC_LIST_UNLINK (updqueue, updrec, r_link); | |
b992d7e2 DN |
265 | minires_freeupdrec (updrec); |
266 | } | |
267 | ||
268 | ||
269 | /* | |
270 | * If this query succeeds, the updater can conclude that the current | |
271 | * client was the last client associated with the domain name, and that | |
272 | * the name now contains the updated A RR. The A RR update is now | |
273 | * complete (and a client updater is finished, while a server would | |
274 | * then proceed to perform a PTR RR update). | |
275 | * -- "Interaction between DHCP and DNS" | |
276 | */ | |
277 | ||
ec64b462 | 278 | if (result == ISC_R_SUCCESS) |
b992d7e2 DN |
279 | return result; |
280 | ||
281 | ||
282 | /* | |
283 | * If the second query fails with NXRRSET, the updater must conclude | |
284 | * that the client's desired name is in use by another host. At this | |
285 | * juncture, the updater can decide (based on some administrative | |
286 | * configuration outside of the scope of this document) whether to let | |
287 | * the existing owner of the name keep that name, and to (possibly) | |
288 | * perform some name disambiguation operation on behalf of the current | |
289 | * client, or to replace the RRs on the name with RRs that represent | |
290 | * the current client. If the configured policy allows replacement of | |
291 | * existing records, the updater submits a query that deletes the | |
292 | * existing A RR and the existing DHCID RR, adding A and DHCID RRs that | |
293 | * represent the IP address and client-identity of the new client. | |
294 | * -- "Interaction between DHCP and DNS" | |
295 | */ | |
296 | ||
297 | return result; | |
298 | ||
299 | ||
300 | error: | |
385fcb27 TL |
301 | while (!ISC_LIST_EMPTY (updqueue)) { |
302 | updrec = ISC_LIST_HEAD (updqueue); | |
303 | ISC_LIST_UNLINK (updqueue, updrec, r_link); | |
b992d7e2 DN |
304 | minires_freeupdrec (updrec); |
305 | } | |
306 | ||
307 | return SERVFAIL; | |
308 | } | |
309 | ||
310 | ||
311 | static ns_rcode ddns_update_ptr (struct data_string *ddns_fwd_name, | |
312 | struct data_string *ddns_rev_name, | |
b992d7e2 DN |
313 | unsigned long ttl) |
314 | { | |
385fcb27 | 315 | ns_updque updqueue; |
b992d7e2 DN |
316 | ns_updrec *updrec; |
317 | ns_rcode result = SERVFAIL; | |
318 | ||
319 | /* | |
320 | * The DHCP server submits a DNS query which deletes all of the PTR RRs | |
321 | * associated with the lease IP address, and adds a PTR RR whose data | |
322 | * is the client's (possibly disambiguated) host name. The server also | |
323 | * adds a DHCID RR specified in Section 4.3. | |
324 | * -- "Interaction between DHCP and DNS" | |
325 | */ | |
326 | ||
385fcb27 | 327 | ISC_LIST_INIT (updqueue); |
b992d7e2 DN |
328 | |
329 | /* | |
330 | * Delete all PTR RRs. | |
331 | */ | |
478028e7 TL |
332 | updrec = minires_mkupdrec (S_UPDATE, |
333 | (const char *)ddns_rev_name -> data, | |
b992d7e2 | 334 | C_IN, T_PTR, 0); |
ec64b462 TL |
335 | if (!updrec) { |
336 | result = ISC_R_NOMEMORY; | |
337 | goto error; | |
338 | } | |
b992d7e2 | 339 | |
478028e7 TL |
340 | updrec -> r_data = (unsigned char *)0; |
341 | updrec -> r_size = 0; | |
b992d7e2 DN |
342 | updrec -> r_opcode = DELETE; |
343 | ||
385fcb27 | 344 | ISC_LIST_APPEND (updqueue, updrec, r_link); |
b992d7e2 | 345 | |
b992d7e2 DN |
346 | /* |
347 | * Add PTR RR. | |
348 | */ | |
478028e7 TL |
349 | updrec = minires_mkupdrec (S_UPDATE, |
350 | (const char *)ddns_rev_name -> data, | |
b992d7e2 | 351 | C_IN, T_PTR, ttl); |
ec64b462 TL |
352 | if (!updrec) { |
353 | result = ISC_R_NOMEMORY; | |
354 | goto error; | |
355 | } | |
b992d7e2 | 356 | |
ee83afae | 357 | updrec -> r_data = ddns_fwd_name -> data; |
478028e7 | 358 | updrec -> r_size = ddns_fwd_name -> len; |
b992d7e2 DN |
359 | updrec -> r_opcode = ADD; |
360 | ||
385fcb27 | 361 | ISC_LIST_APPEND (updqueue, updrec, r_link); |
b992d7e2 | 362 | |
b992d7e2 DN |
363 | /* |
364 | * Attempt to perform the update. | |
365 | */ | |
385fcb27 TL |
366 | result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue)); |
367 | print_dns_status ((int)result, &updqueue); | |
b992d7e2 DN |
368 | |
369 | /* Fall through. */ | |
ec64b462 | 370 | error: |
b992d7e2 | 371 | |
385fcb27 TL |
372 | while (!ISC_LIST_EMPTY (updqueue)) { |
373 | updrec = ISC_LIST_HEAD (updqueue); | |
374 | ISC_LIST_UNLINK (updqueue, updrec, r_link); | |
b992d7e2 DN |
375 | minires_freeupdrec (updrec); |
376 | } | |
377 | ||
378 | return result; | |
379 | } | |
380 | ||
381 | ||
382 | static ns_rcode ddns_remove_a (struct data_string *ddns_fwd_name, | |
bdad826f | 383 | struct iaddr ddns_addr, |
b992d7e2 DN |
384 | struct data_string *ddns_dhcid) |
385 | { | |
385fcb27 | 386 | ns_updque updqueue; |
b992d7e2 DN |
387 | ns_updrec *updrec; |
388 | ns_rcode result = SERVFAIL; | |
bdad826f TL |
389 | char ddns_address [16]; |
390 | ||
391 | if (ddns_addr.len != 4) | |
392 | return SERVFAIL; | |
393 | ||
394 | #ifndef NO_SNPRINTF | |
395 | snprintf (ddns_address, 16, "%d.%d.%d.%d", | |
396 | ddns_addr.iabuf[0], ddns_addr.iabuf[1], | |
397 | ddns_addr.iabuf[2], ddns_addr.iabuf[3]); | |
398 | #else | |
399 | sprintf (ddns_address, "%d.%d.%d.%d", | |
400 | ddns_addr.iabuf[0], ddns_addr.iabuf[1], | |
401 | ddns_addr.iabuf[2], ddns_addr.iabuf[3]); | |
402 | #endif | |
403 | ||
b992d7e2 DN |
404 | |
405 | /* | |
406 | * The entity chosen to handle the A record for this client (either the | |
407 | * client or the server) SHOULD delete the A record that was added when | |
408 | * the lease was made to the client. | |
409 | * | |
410 | * In order to perform this delete, the updater prepares an UPDATE | |
411 | * query which contains two prerequisites. The first prerequisite | |
412 | * asserts that the DHCID RR exists whose data is the client identity | |
413 | * described in Section 4.3. The second prerequisite asserts that the | |
414 | * data in the A RR contains the IP address of the lease that has | |
415 | * expired or been released. | |
416 | * -- "Interaction between DHCP and DNS" | |
417 | */ | |
418 | ||
385fcb27 | 419 | ISC_LIST_INIT (updqueue); |
b992d7e2 DN |
420 | |
421 | /* | |
422 | * DHCID RR exists, and matches client identity. | |
423 | */ | |
87fec475 TL |
424 | updrec = minires_mkupdrec (S_PREREQ, |
425 | (const char *)ddns_fwd_name -> data, | |
b992d7e2 | 426 | C_IN, T_DHCID,0); |
ec64b462 TL |
427 | if (!updrec) { |
428 | result = ISC_R_NOMEMORY; | |
429 | goto error; | |
430 | } | |
b992d7e2 | 431 | |
ee83afae | 432 | updrec -> r_data = ddns_dhcid -> data; |
b992d7e2 DN |
433 | updrec -> r_size = ddns_dhcid -> len; |
434 | updrec -> r_opcode = YXRRSET; | |
435 | ||
385fcb27 | 436 | ISC_LIST_APPEND (updqueue, updrec, r_link); |
b992d7e2 DN |
437 | |
438 | ||
439 | /* | |
440 | * A RR matches the expiring lease. | |
441 | */ | |
87fec475 TL |
442 | updrec = minires_mkupdrec (S_PREREQ, |
443 | (const char *)ddns_fwd_name -> data, | |
b992d7e2 | 444 | C_IN, T_A, 0); |
ec64b462 TL |
445 | if (!updrec) { |
446 | result = ISC_R_NOMEMORY; | |
447 | goto error; | |
448 | } | |
b992d7e2 | 449 | |
87fec475 | 450 | updrec -> r_data = (unsigned char *)ddns_address; |
bdad826f | 451 | updrec -> r_size = strlen (ddns_address); |
b992d7e2 DN |
452 | updrec -> r_opcode = YXRRSET; |
453 | ||
385fcb27 | 454 | ISC_LIST_APPEND (updqueue, updrec, r_link); |
b992d7e2 DN |
455 | |
456 | ||
457 | /* | |
458 | * Delete appropriate A RR. | |
459 | */ | |
87fec475 TL |
460 | updrec = minires_mkupdrec (S_UPDATE, |
461 | (const char *)ddns_fwd_name -> data, | |
b992d7e2 | 462 | C_IN, T_A, 0); |
ec64b462 TL |
463 | if (!updrec) { |
464 | result = ISC_R_NOMEMORY; | |
465 | goto error; | |
466 | } | |
b992d7e2 | 467 | |
87fec475 | 468 | updrec -> r_data = (unsigned char *)ddns_address; |
478028e7 | 469 | updrec -> r_size = strlen (ddns_address); |
b992d7e2 DN |
470 | updrec -> r_opcode = DELETE; |
471 | ||
385fcb27 | 472 | ISC_LIST_APPEND (updqueue, updrec, r_link); |
b992d7e2 | 473 | |
b992d7e2 DN |
474 | /* |
475 | * Attempt to perform the update. | |
476 | */ | |
385fcb27 TL |
477 | result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue)); |
478 | print_dns_status ((int)result, &updqueue); | |
b992d7e2 DN |
479 | |
480 | /* | |
481 | * If the query fails, the updater MUST NOT delete the DNS name. It | |
482 | * may be that the host whose lease on the server has expired has moved | |
483 | * to another network and obtained a lease from a different server, | |
484 | * which has caused the client's A RR to be replaced. It may also be | |
485 | * that some other client has been configured with a name that matches | |
486 | * the name of the DHCP client, and the policy was that the last client | |
487 | * to specify the name would get the name. In this case, the DHCID RR | |
488 | * will no longer match the updater's notion of the client-identity of | |
489 | * the host pointed to by the DNS name. | |
490 | * -- "Interaction between DHCP and DNS" | |
491 | */ | |
492 | ||
ec64b462 | 493 | if (result != ISC_R_SUCCESS) |
bdad826f TL |
494 | goto error; |
495 | ||
496 | while (!ISC_LIST_EMPTY (updqueue)) { | |
497 | updrec = ISC_LIST_HEAD (updqueue); | |
498 | ISC_LIST_UNLINK (updqueue, updrec, r_link); | |
499 | minires_freeupdrec (updrec); | |
500 | } | |
501 | ||
502 | /* If the deletion of the A succeeded, and there are no A records | |
503 | left for this domain, then we can blow away the DHCID record | |
504 | as well. We can't blow away the DHCID record above because | |
505 | it's possible that more than one A has been added to this | |
506 | domain name. */ | |
507 | ISC_LIST_INIT (updqueue); | |
508 | ||
509 | /* | |
510 | * A RR does not exist. | |
511 | */ | |
87fec475 TL |
512 | updrec = minires_mkupdrec (S_PREREQ, |
513 | (const char *)ddns_fwd_name -> data, | |
bdad826f | 514 | C_IN, T_A, 0); |
ec64b462 TL |
515 | if (!updrec) { |
516 | result = ISC_R_NOMEMORY; | |
517 | goto error; | |
518 | } | |
bdad826f | 519 | |
478028e7 | 520 | updrec -> r_data = (unsigned char *)0; |
bdad826f TL |
521 | updrec -> r_size = 0; |
522 | updrec -> r_opcode = NXRRSET; | |
523 | ||
524 | ISC_LIST_APPEND (updqueue, updrec, r_link); | |
525 | ||
526 | /* | |
527 | * Delete appropriate DHCID RR. | |
528 | */ | |
87fec475 TL |
529 | updrec = minires_mkupdrec (S_UPDATE, |
530 | (const char *)ddns_fwd_name -> data, | |
bdad826f | 531 | C_IN, T_DHCID, 0); |
ec64b462 TL |
532 | if (!updrec) { |
533 | result = ISC_R_NOMEMORY; | |
bdad826f | 534 | goto error; |
ec64b462 | 535 | } |
bdad826f | 536 | |
ee83afae | 537 | updrec -> r_data = ddns_dhcid -> data; |
478028e7 | 538 | updrec -> r_size = ddns_dhcid -> len; |
bdad826f TL |
539 | updrec -> r_opcode = DELETE; |
540 | ||
541 | ISC_LIST_APPEND (updqueue, updrec, r_link); | |
542 | ||
543 | /* | |
544 | * Attempt to perform the update. | |
545 | */ | |
546 | result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue)); | |
547 | print_dns_status ((int)result, &updqueue); | |
b992d7e2 DN |
548 | |
549 | /* Fall through. */ | |
550 | error: | |
551 | ||
385fcb27 TL |
552 | while (!ISC_LIST_EMPTY (updqueue)) { |
553 | updrec = ISC_LIST_HEAD (updqueue); | |
554 | ISC_LIST_UNLINK (updqueue, updrec, r_link); | |
b992d7e2 DN |
555 | minires_freeupdrec (updrec); |
556 | } | |
557 | ||
558 | return result; | |
559 | } | |
560 | ||
561 | ||
ee83afae | 562 | static ns_rcode ddns_remove_ptr (struct data_string *ddns_rev_name) |
b992d7e2 | 563 | { |
385fcb27 | 564 | ns_updque updqueue; |
b992d7e2 | 565 | ns_updrec *updrec; |
ec64b462 | 566 | isc_result_t result; |
b992d7e2 DN |
567 | |
568 | /* | |
569 | * When a lease expires or a DHCP client issues a DHCPRELEASE request, | |
570 | * the DHCP server SHOULD delete the PTR RR that matches the DHCP | |
571 | * binding, if one was successfully added. The server's update query | |
572 | * SHOULD assert that the name in the PTR record matches the name of | |
573 | * the client whose lease has expired or been released. | |
574 | * -- "Interaction between DHCP and DNS" | |
575 | */ | |
576 | ||
385fcb27 | 577 | ISC_LIST_INIT (updqueue); |
b992d7e2 DN |
578 | |
579 | /* | |
ee83afae | 580 | * Delete the PTR RRset for the leased address. |
b992d7e2 | 581 | */ |
478028e7 TL |
582 | updrec = minires_mkupdrec (S_UPDATE, |
583 | (const char *)ddns_rev_name -> data, | |
b992d7e2 | 584 | C_IN, T_PTR, 0); |
ec64b462 TL |
585 | if (!updrec) { |
586 | result = ISC_R_NOMEMORY; | |
587 | goto error; | |
588 | } | |
b992d7e2 | 589 | |
ee83afae TL |
590 | updrec -> r_data = (unsigned char *)0; |
591 | updrec -> r_size = 0; | |
b992d7e2 DN |
592 | updrec -> r_opcode = DELETE; |
593 | ||
385fcb27 | 594 | ISC_LIST_APPEND (updqueue, updrec, r_link); |
b992d7e2 | 595 | |
b992d7e2 DN |
596 | /* |
597 | * Attempt to perform the update. | |
598 | */ | |
385fcb27 TL |
599 | result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue)); |
600 | print_dns_status ((int)result, &updqueue); | |
b992d7e2 DN |
601 | |
602 | /* Fall through. */ | |
ec64b462 | 603 | error: |
b992d7e2 | 604 | |
385fcb27 TL |
605 | while (!ISC_LIST_EMPTY (updqueue)) { |
606 | updrec = ISC_LIST_HEAD (updqueue); | |
607 | ISC_LIST_UNLINK (updqueue, updrec, r_link); | |
b992d7e2 DN |
608 | minires_freeupdrec (updrec); |
609 | } | |
610 | ||
611 | return result; | |
612 | } | |
613 | ||
614 | ||
615 | int ddns_updates (struct packet *packet, | |
ec64b462 | 616 | struct lease *lease, struct lease *old, |
b992d7e2 DN |
617 | struct lease_state *state) |
618 | { | |
619 | unsigned long ddns_ttl = DEFAULT_DDNS_TTL; | |
620 | struct data_string ddns_hostname; | |
621 | struct data_string ddns_domainname; | |
478028e7 | 622 | struct data_string old_ddns_fwd_name; |
b992d7e2 DN |
623 | struct data_string ddns_fwd_name; |
624 | struct data_string ddns_rev_name; | |
b992d7e2 DN |
625 | struct data_string ddns_dhcid; |
626 | unsigned len; | |
b992d7e2 DN |
627 | struct data_string d1; |
628 | struct option_cache *oc; | |
629 | int s1, s2; | |
630 | int result = 0; | |
ec64b462 | 631 | isc_result_t rcode1 = ISC_R_SUCCESS, rcode2 = ISC_R_SUCCESS; |
478028e7 TL |
632 | int server_updates_a = 1; |
633 | struct buffer *bp = (struct buffer *)0; | |
634 | int ignorep = 0; | |
b992d7e2 | 635 | |
5fac73d6 TL |
636 | if (ddns_update_style != 2) |
637 | return 0; | |
638 | ||
b992d7e2 DN |
639 | /* Can only cope with IPv4 addrs at the moment. */ |
640 | if (lease -> ip_addr . len != 4) | |
641 | return 0; | |
642 | ||
b992d7e2 DN |
643 | memset (&ddns_hostname, 0, sizeof (ddns_hostname)); |
644 | memset (&ddns_domainname, 0, sizeof (ddns_domainname)); | |
478028e7 | 645 | memset (&old_ddns_fwd_name, 0, sizeof (ddns_fwd_name)); |
b992d7e2 DN |
646 | memset (&ddns_fwd_name, 0, sizeof (ddns_fwd_name)); |
647 | memset (&ddns_rev_name, 0, sizeof (ddns_rev_name)); | |
b992d7e2 DN |
648 | memset (&ddns_dhcid, 0, sizeof (ddns_dhcid)); |
649 | ||
478028e7 TL |
650 | /* If we are allowed to accept the client's update of its own A |
651 | record, see if the client wants to update its own A record. */ | |
652 | if (!(oc = lookup_option (&server_universe, state -> options, | |
ebd0310b | 653 | SV_CLIENT_UPDATES)) || |
478028e7 | 654 | evaluate_boolean_option_cache (&ignorep, packet, lease, |
b992d7e2 DN |
655 | (struct client_state *)0, |
656 | packet -> options, | |
657 | state -> options, | |
658 | &lease -> scope, oc, MDL)) { | |
478028e7 TL |
659 | /* If there's no fqdn.no-client-update or if it's |
660 | nonzero, don't try to use the client-supplied | |
661 | XXX */ | |
ee83afae | 662 | if (!(oc = lookup_option (&fqdn_universe, packet -> options, |
478028e7 TL |
663 | FQDN_NO_CLIENT_UPDATE)) || |
664 | evaluate_boolean_option_cache (&ignorep, packet, lease, | |
665 | (struct client_state *)0, | |
666 | packet -> options, | |
667 | state -> options, | |
668 | &lease -> scope, oc, MDL)) | |
669 | goto noclient; | |
e9d45f83 TL |
670 | /* Win98 and Win2k will happily claim to be willing to |
671 | update an unqualified domain name. */ | |
672 | if (!(oc = lookup_option (&fqdn_universe, packet -> options, | |
673 | FQDN_DOMAINNAME))) | |
674 | goto noclient; | |
ee83afae | 675 | if (!(oc = lookup_option (&fqdn_universe, packet -> options, |
478028e7 | 676 | FQDN_FQDN)) || |
ee83afae TL |
677 | !evaluate_option_cache (&ddns_fwd_name, packet, lease, |
678 | (struct client_state *)0, | |
679 | packet -> options, | |
680 | state -> options, | |
681 | &lease -> scope, oc, MDL)) | |
478028e7 TL |
682 | goto noclient; |
683 | server_updates_a = 0; | |
684 | goto client_updates; | |
b992d7e2 | 685 | } |
478028e7 | 686 | noclient: |
b992d7e2 | 687 | |
ec64b462 TL |
688 | /* If it's a static lease, then don't do the DNS update unless we're |
689 | specifically configured to do so. If the client asked to do its | |
690 | own update and we allowed that, we don't do this test. */ | |
691 | if (lease -> flags & STATIC_LEASE) { | |
692 | if (!(oc = lookup_option (&fqdn_universe, packet -> options, | |
693 | SV_UPDATE_STATIC_LEASES)) || | |
694 | !evaluate_boolean_option_cache (&ignorep, packet, lease, | |
695 | (struct client_state *)0, | |
696 | packet -> options, | |
697 | state -> options, | |
698 | &lease -> scope, oc, MDL)) | |
699 | return 0; | |
700 | } | |
701 | ||
b992d7e2 | 702 | /* |
478028e7 | 703 | * Compute the name for the A record. |
b992d7e2 DN |
704 | */ |
705 | s1 = s2 = 0; | |
706 | ||
707 | oc = lookup_option (&server_universe, state -> options, | |
708 | SV_DDNS_HOST_NAME); | |
709 | if (oc) | |
710 | s1 = evaluate_option_cache (&ddns_hostname, packet, lease, | |
711 | (struct client_state *)0, | |
712 | packet -> options, | |
713 | state -> options, | |
714 | &lease -> scope, oc, MDL); | |
715 | ||
716 | oc = lookup_option (&server_universe, state -> options, | |
717 | SV_DDNS_DOMAIN_NAME); | |
718 | if (oc) | |
719 | s2 = evaluate_option_cache (&ddns_domainname, packet, lease, | |
720 | (struct client_state *)0, | |
721 | packet -> options, | |
722 | state -> options, | |
723 | &lease -> scope, oc, MDL); | |
724 | ||
725 | if (s1 && s2) { | |
726 | buffer_allocate (&ddns_fwd_name.buffer, | |
727 | ddns_hostname.len + ddns_domainname.len + 2, | |
728 | MDL); | |
729 | if (ddns_fwd_name.buffer) { | |
730 | ddns_fwd_name.data = ddns_fwd_name.buffer -> data; | |
731 | data_string_append (&ddns_fwd_name, &ddns_hostname); | |
732 | ddns_fwd_name.buffer -> data [ddns_fwd_name.len] = '.'; | |
733 | ddns_fwd_name.len++; | |
734 | data_string_append (&ddns_fwd_name, &ddns_domainname); | |
735 | ddns_fwd_name.buffer -> data [ddns_fwd_name.len] ='\0'; | |
736 | ddns_fwd_name.terminated = 1; | |
737 | } | |
738 | } | |
478028e7 TL |
739 | client_updates: |
740 | ||
741 | /* See if there's a name already stored on the lease. */ | |
742 | if (find_bound_string (&old_ddns_fwd_name, | |
743 | lease -> scope, "ddns-fwd-name")) { | |
744 | /* If there is, see if it's different. */ | |
745 | if (old_ddns_fwd_name.len != ddns_fwd_name.len || | |
746 | memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data, | |
747 | old_ddns_fwd_name.len)) { | |
748 | /* If the name is different, try to delete | |
749 | the old A record. */ | |
750 | if (!ddns_removals (lease)) | |
751 | goto out; | |
752 | /* If the delete succeeded, go install the new | |
753 | record. */ | |
754 | goto in; | |
755 | } | |
756 | ||
757 | /* See if there's a DHCID on the lease. */ | |
758 | if (!find_bound_string (&ddns_dhcid, | |
759 | lease -> scope, "ddns-txt")) { | |
760 | /* If there's no DHCID, the update was probably | |
761 | done with the old-style ad-hoc DDNS updates. | |
762 | So if the expiry and release events look like | |
763 | they're the same, run them. This should delete | |
764 | the old DDNS data. */ | |
ec64b462 | 765 | if (old -> on_expiry == old -> on_release) { |
478028e7 TL |
766 | execute_statements ((struct binding_value **)0, |
767 | (struct packet *)0, lease, | |
768 | (struct client_state *)0, | |
769 | (struct option_state *)0, | |
770 | (struct option_state *)0, | |
771 | &lease -> scope, | |
ec64b462 TL |
772 | old -> on_expiry); |
773 | if (old -> on_expiry) | |
478028e7 | 774 | executable_statement_dereference |
ec64b462 TL |
775 | (&old -> on_expiry, MDL); |
776 | if (old -> on_release) | |
478028e7 | 777 | executable_statement_dereference |
ec64b462 | 778 | (&old -> on_release, MDL); |
478028e7 TL |
779 | /* Now, install the DDNS data the new way. */ |
780 | goto in; | |
781 | } | |
782 | } | |
783 | ||
ebd0310b TL |
784 | /* See if the administrator wants to do updates even |
785 | in cases where the update already appears to have been | |
786 | done. */ | |
787 | if (!(oc = lookup_option (&server_universe, state -> options, | |
788 | SV_UPDATE_OPTIMIZATION)) || | |
789 | evaluate_boolean_option_cache (&ignorep, packet, lease, | |
790 | (struct client_state *)0, | |
791 | packet -> options, | |
792 | state -> options, | |
793 | &lease -> scope, oc, MDL)) { | |
794 | result = 1; | |
795 | goto noerror; | |
796 | } | |
478028e7 | 797 | } |
b992d7e2 | 798 | |
478028e7 TL |
799 | /* If there's no ddns-fwd-name on the lease, see if there's |
800 | a ddns-client-fqdn, indicating a prior client FQDN update. | |
801 | If there is, and if we're still doing the client update, | |
802 | see if the name has changed. If it hasn't, don't do the | |
803 | PTR update. */ | |
804 | if (find_bound_string (&old_ddns_fwd_name, | |
805 | lease -> scope, "ddns-client-fqdn")) { | |
ee83afae TL |
806 | if (old_ddns_fwd_name.len == ddns_fwd_name.len && |
807 | !memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data, | |
808 | old_ddns_fwd_name.len)) { | |
478028e7 TL |
809 | /* If the name is not different, no need to update |
810 | the PTR record. */ | |
811 | goto noerror; | |
812 | } | |
813 | } | |
814 | in: | |
815 | ||
b992d7e2 | 816 | /* |
478028e7 TL |
817 | * Compute the RR TTL. |
818 | */ | |
819 | ddns_ttl = DEFAULT_DDNS_TTL; | |
820 | memset (&d1, 0, sizeof d1); | |
821 | if ((oc = lookup_option (&server_universe, state -> options, | |
822 | SV_DDNS_TTL))) { | |
823 | if (evaluate_option_cache (&d1, packet, lease, | |
824 | (struct client_state *)0, | |
825 | packet -> options, | |
826 | state -> options, | |
827 | &lease -> scope, oc, MDL)) { | |
828 | if (d1.len == sizeof (u_int32_t)) | |
829 | ddns_ttl = getULong (d1.data); | |
830 | data_string_forget (&d1, MDL); | |
831 | } | |
832 | } | |
833 | ||
834 | ||
835 | /* | |
836 | * Compute the reverse IP name. | |
b992d7e2 DN |
837 | */ |
838 | oc = lookup_option (&server_universe, state -> options, | |
839 | SV_DDNS_REV_DOMAIN_NAME); | |
840 | if (oc) | |
841 | s1 = evaluate_option_cache (&d1, packet, lease, | |
842 | (struct client_state *)0, | |
843 | packet -> options, | |
844 | state -> options, | |
845 | &lease -> scope, oc, MDL); | |
846 | ||
847 | if (oc && s1) { | |
848 | /* Buffer length: | |
849 | XXX.XXX.XXX.XXX.<ddns-rev-domain-name>\0 */ | |
850 | buffer_allocate (&ddns_rev_name.buffer, | |
851 | d1.len + 17, MDL); | |
852 | if (ddns_rev_name.buffer) { | |
853 | ddns_rev_name.data = ddns_rev_name.buffer -> data; | |
854 | #ifndef NO_SNPRINTF | |
87fec475 | 855 | snprintf ((char *)ddns_rev_name.buffer -> data, 17, |
b992d7e2 DN |
856 | "%d.%d.%d.%d.", |
857 | lease -> ip_addr . iabuf[3], | |
858 | lease -> ip_addr . iabuf[2], | |
859 | lease -> ip_addr . iabuf[1], | |
860 | lease -> ip_addr . iabuf[0]); | |
861 | #else | |
87fec475 | 862 | sprintf ((char *)ddns_rev_name.buffer -> data, |
b992d7e2 DN |
863 | "%d.%d.%d.%d.", |
864 | lease -> ip_addr . iabuf[3], | |
865 | lease -> ip_addr . iabuf[2], | |
866 | lease -> ip_addr . iabuf[1], | |
867 | lease -> ip_addr . iabuf[0]); | |
868 | #endif | |
478028e7 TL |
869 | ddns_rev_name.len = |
870 | strlen ((const char *)ddns_rev_name.data); | |
b992d7e2 DN |
871 | data_string_append (&ddns_rev_name, &d1); |
872 | ddns_rev_name.buffer -> data [ddns_rev_name.len] ='\0'; | |
873 | ddns_rev_name.terminated = 1; | |
874 | } | |
875 | ||
876 | data_string_forget (&d1, MDL); | |
877 | } | |
878 | ||
b992d7e2 | 879 | /* |
478028e7 | 880 | * If we are updating the A record, compute the DHCID value. |
b992d7e2 | 881 | */ |
478028e7 TL |
882 | if (server_updates_a) { |
883 | memset (&ddns_dhcid, 0, sizeof ddns_dhcid); | |
884 | get_dhcid (&ddns_dhcid, lease); | |
885 | } | |
b992d7e2 | 886 | |
b992d7e2 DN |
887 | /* |
888 | * Start the resolver, if necessary. | |
889 | */ | |
890 | if (!resolver_inited) { | |
891 | minires_ninit (&resolver_state); | |
892 | resolver_inited = 1; | |
ec64b462 TL |
893 | resolver_state.retrans = 1; |
894 | resolver_state.retry = 1; | |
b992d7e2 DN |
895 | } |
896 | ||
b992d7e2 DN |
897 | /* |
898 | * Perform updates. | |
899 | */ | |
bdad826f TL |
900 | if (ddns_fwd_name.len && ddns_dhcid.len) |
901 | rcode1 = ddns_update_a (&ddns_fwd_name, lease -> ip_addr, | |
902 | &ddns_dhcid, ddns_ttl); | |
b992d7e2 | 903 | |
ec64b462 | 904 | if (rcode1 == ISC_R_SUCCESS) { |
478028e7 | 905 | if (ddns_fwd_name.len && ddns_rev_name.len) |
bdad826f TL |
906 | rcode2 = ddns_update_ptr (&ddns_fwd_name, |
907 | &ddns_rev_name, ddns_ttl); | |
908 | } else | |
ec64b462 | 909 | rcode2 = rcode1; |
b992d7e2 | 910 | |
ec64b462 TL |
911 | if (rcode1 == ISC_R_SUCCESS && |
912 | (server_updates_a || rcode2 == ISC_R_SUCCESS)) { | |
478028e7 TL |
913 | bind_ds_value (&lease -> scope, |
914 | (server_updates_a | |
915 | ? "ddns-fwd-name" : "ddns-client-fqdn"), | |
b992d7e2 | 916 | &ddns_fwd_name); |
ee83afae TL |
917 | if (server_updates_a) |
918 | bind_ds_value (&lease -> scope, "ddns-txt", | |
919 | &ddns_dhcid); | |
b992d7e2 | 920 | } |
bdad826f | 921 | |
ec64b462 | 922 | if (rcode2 == ISC_R_SUCCESS) { |
b992d7e2 DN |
923 | bind_ds_value (&lease -> scope, "ddns-rev-name", |
924 | &ddns_rev_name); | |
925 | } | |
926 | ||
478028e7 | 927 | /* Set up the outgoing FQDN option if there was an incoming |
ee83afae TL |
928 | FQDN option. If there's a valid FQDN option, there should |
929 | be an FQDN_ENCODED suboption, so we test the latter to | |
930 | detect the presence of the former. */ | |
478028e7 | 931 | noerror: |
ee83afae TL |
932 | if ((oc = lookup_option (&fqdn_universe, |
933 | packet -> options, FQDN_ENCODED)) | |
478028e7 TL |
934 | && buffer_allocate (&bp, ddns_fwd_name.len + 5, MDL)) { |
935 | bp -> data [0] = server_updates_a; | |
936 | if (!save_option_buffer (&fqdn_universe, state -> options, | |
937 | bp, &bp -> data [0], 1, | |
938 | &fqdn_options [FQDN_SERVER_UPDATE], | |
939 | 0)) | |
940 | goto badfqdn; | |
941 | bp -> data [1] = server_updates_a; | |
942 | if (!save_option_buffer (&fqdn_universe, state -> options, | |
943 | bp, &bp -> data [1], 1, | |
944 | &fqdn_options [FQDN_NO_CLIENT_UPDATE], | |
945 | 0)) | |
946 | goto badfqdn; | |
947 | /* Do the same encoding the client did. */ | |
948 | oc = lookup_option (&fqdn_universe, packet -> options, | |
949 | FQDN_ENCODED); | |
950 | if (oc && | |
951 | evaluate_boolean_option_cache (&ignorep, packet, lease, | |
952 | (struct client_state *)0, | |
953 | packet -> options, | |
954 | state -> options, | |
955 | &lease -> scope, oc, MDL)) | |
956 | bp -> data [2] = 1; | |
957 | else | |
958 | bp -> data [2] = 0; | |
959 | if (!save_option_buffer (&fqdn_universe, state -> options, | |
960 | bp, &bp -> data [2], 1, | |
961 | &fqdn_options [FQDN_ENCODED], | |
962 | 0)) | |
963 | goto badfqdn; | |
ec64b462 | 964 | bp -> data [3] = isc_rcode_to_ns (rcode1); |
478028e7 TL |
965 | if (!save_option_buffer (&fqdn_universe, state -> options, |
966 | bp, &bp -> data [3], 1, | |
967 | &fqdn_options [FQDN_RCODE1], | |
968 | 0)) | |
969 | goto badfqdn; | |
ec64b462 | 970 | bp -> data [4] = isc_rcode_to_ns (rcode2); |
478028e7 TL |
971 | if (!save_option_buffer (&fqdn_universe, state -> options, |
972 | bp, &bp -> data [4], 1, | |
973 | &fqdn_options [FQDN_RCODE2], | |
974 | 0)) | |
975 | goto badfqdn; | |
976 | if (ddns_fwd_name.len) { | |
977 | memcpy (&bp -> data [5], | |
978 | ddns_fwd_name.data, ddns_fwd_name.len); | |
979 | if (!save_option_buffer (&fqdn_universe, state -> options, | |
980 | bp, &bp -> data [5], | |
981 | ddns_fwd_name.len, | |
982 | &fqdn_options [FQDN_FQDN], | |
983 | 0)) | |
984 | goto badfqdn; | |
985 | } | |
b992d7e2 DN |
986 | } |
987 | ||
478028e7 TL |
988 | badfqdn: |
989 | out: | |
b992d7e2 DN |
990 | /* |
991 | * Final cleanup. | |
992 | */ | |
993 | data_string_forget (&ddns_hostname, MDL); | |
994 | data_string_forget (&ddns_domainname, MDL); | |
478028e7 | 995 | data_string_forget (&old_ddns_fwd_name, MDL); |
b992d7e2 DN |
996 | data_string_forget (&ddns_fwd_name, MDL); |
997 | data_string_forget (&ddns_rev_name, MDL); | |
b992d7e2 DN |
998 | data_string_forget (&ddns_dhcid, MDL); |
999 | ||
478028e7 | 1000 | return result; |
b992d7e2 DN |
1001 | } |
1002 | ||
478028e7 | 1003 | int ddns_removals (struct lease *lease) |
385fcb27 | 1004 | { |
b992d7e2 DN |
1005 | struct data_string ddns_fwd_name; |
1006 | struct data_string ddns_rev_name; | |
b992d7e2 | 1007 | struct data_string ddns_dhcid; |
ec64b462 | 1008 | isc_result_t rcode; |
385fcb27 | 1009 | struct binding *binding; |
478028e7 | 1010 | int result = 0; |
ee83afae | 1011 | int client_updated = 0; |
b992d7e2 DN |
1012 | |
1013 | /* No scope implies that DDNS has not been performed for this lease. */ | |
1014 | if (!lease -> scope) | |
478028e7 | 1015 | return 0; |
b992d7e2 | 1016 | |
b992d7e2 DN |
1017 | /* |
1018 | * Look up stored names. | |
1019 | */ | |
1020 | memset (&ddns_fwd_name, 0, sizeof (ddns_fwd_name)); | |
1021 | memset (&ddns_rev_name, 0, sizeof (ddns_rev_name)); | |
b992d7e2 DN |
1022 | memset (&ddns_dhcid, 0, sizeof (ddns_dhcid)); |
1023 | ||
b992d7e2 DN |
1024 | /* |
1025 | * Start the resolver, if necessary. | |
1026 | */ | |
1027 | if (!resolver_inited) { | |
1028 | minires_ninit (&resolver_state); | |
1029 | resolver_inited = 1; | |
1030 | } | |
1031 | ||
478028e7 TL |
1032 | /* We need the fwd name whether we are deleting both records or just |
1033 | the PTR record, so if it's not there, we can't proceed. */ | |
1034 | if (!find_bound_string (&ddns_fwd_name, | |
ee83afae TL |
1035 | lease -> scope, "ddns-fwd-name")) { |
1036 | /* If there's no ddns-fwd-name, look for the client fqdn, | |
1037 | in case the client did the update. */ | |
1038 | if (!find_bound_string (&ddns_fwd_name, | |
1039 | lease -> scope, "ddns-client-fqdn")) | |
1040 | return 0; | |
1041 | client_updated = 1; | |
1042 | goto try_rev; | |
1043 | } | |
478028e7 TL |
1044 | |
1045 | /* If the ddns-txt binding isn't there, this isn't an interim | |
1046 | or rfc3??? record, so we can't delete the A record using | |
1047 | this mechanism, but we can delete the PTR record. */ | |
1048 | if (!find_bound_string (&ddns_dhcid, lease -> scope, "ddns-txt")) { | |
1049 | result = 1; | |
1050 | goto try_rev; | |
1051 | } | |
1052 | ||
b992d7e2 DN |
1053 | /* |
1054 | * Perform removals. | |
1055 | */ | |
478028e7 TL |
1056 | rcode = ddns_remove_a (&ddns_fwd_name, lease -> ip_addr, &ddns_dhcid); |
1057 | ||
ec64b462 | 1058 | if (rcode == ISC_R_SUCCESS) { |
478028e7 TL |
1059 | result = 1; |
1060 | unset (lease -> scope, "ddns-fwd-name"); | |
1061 | unset (lease -> scope, "ddns-txt"); | |
1062 | try_rev: | |
1063 | if (find_bound_string (&ddns_rev_name, | |
1064 | lease -> scope, "ddns-rev-name")) { | |
ee83afae | 1065 | if (ddns_remove_ptr(&ddns_rev_name) == NOERROR) { |
478028e7 | 1066 | unset (lease -> scope, "ddns-rev-name"); |
ee83afae TL |
1067 | if (client_updated) |
1068 | unset (lease -> scope, | |
1069 | "ddns-client-fqdn"); | |
1070 | } else | |
478028e7 TL |
1071 | result = 0; |
1072 | } | |
b992d7e2 DN |
1073 | } |
1074 | ||
b992d7e2 DN |
1075 | data_string_forget (&ddns_fwd_name, MDL); |
1076 | data_string_forget (&ddns_rev_name, MDL); | |
b992d7e2 DN |
1077 | data_string_forget (&ddns_dhcid, MDL); |
1078 | ||
478028e7 | 1079 | return result; |
b992d7e2 DN |
1080 | } |
1081 | ||
b992d7e2 | 1082 | #endif /* NSUPDATE */ |