xref: /minix3/external/bsd/dhcp/dist/server/ddns.c (revision 83ee113ee0d94f3844d44065af2311604e9a30ad)
1*83ee113eSDavid van Moolenbroek /*	$NetBSD: ddns.c,v 1.4 2014/07/12 12:09:38 spz Exp $	*/
2*83ee113eSDavid van Moolenbroek /* ddns.c
3*83ee113eSDavid van Moolenbroek 
4*83ee113eSDavid van Moolenbroek    Dynamic DNS updates. */
5*83ee113eSDavid van Moolenbroek 
6*83ee113eSDavid van Moolenbroek /*
7*83ee113eSDavid van Moolenbroek  *
8*83ee113eSDavid van Moolenbroek  * Copyright (c) 2009-2014 by Internet Systems Consortium, Inc. ("ISC")
9*83ee113eSDavid van Moolenbroek  * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
10*83ee113eSDavid van Moolenbroek  * Copyright (c) 2000-2003 by Internet Software Consortium
11*83ee113eSDavid van Moolenbroek  *
12*83ee113eSDavid van Moolenbroek  * Permission to use, copy, modify, and distribute this software for any
13*83ee113eSDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
14*83ee113eSDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
15*83ee113eSDavid van Moolenbroek  *
16*83ee113eSDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
17*83ee113eSDavid van Moolenbroek  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
18*83ee113eSDavid van Moolenbroek  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
19*83ee113eSDavid van Moolenbroek  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20*83ee113eSDavid van Moolenbroek  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
21*83ee113eSDavid van Moolenbroek  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
22*83ee113eSDavid van Moolenbroek  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23*83ee113eSDavid van Moolenbroek  *
24*83ee113eSDavid van Moolenbroek  *   Internet Systems Consortium, Inc.
25*83ee113eSDavid van Moolenbroek  *   950 Charter Street
26*83ee113eSDavid van Moolenbroek  *   Redwood City, CA 94063
27*83ee113eSDavid van Moolenbroek  *   <info@isc.org>
28*83ee113eSDavid van Moolenbroek  *   https://www.isc.org/
29*83ee113eSDavid van Moolenbroek  *
30*83ee113eSDavid van Moolenbroek  * This software has been donated to Internet Systems Consortium
31*83ee113eSDavid van Moolenbroek  * by Damien Neil of Nominum, Inc.
32*83ee113eSDavid van Moolenbroek  *
33*83ee113eSDavid van Moolenbroek  * To learn more about Internet Systems Consortium, see
34*83ee113eSDavid van Moolenbroek  * ``https://www.isc.org/''.   To learn more about Nominum, Inc., see
35*83ee113eSDavid van Moolenbroek  * ``http://www.nominum.com''.
36*83ee113eSDavid van Moolenbroek  */
37*83ee113eSDavid van Moolenbroek 
38*83ee113eSDavid van Moolenbroek #include <sys/cdefs.h>
39*83ee113eSDavid van Moolenbroek __RCSID("$NetBSD: ddns.c,v 1.4 2014/07/12 12:09:38 spz Exp $");
40*83ee113eSDavid van Moolenbroek 
41*83ee113eSDavid van Moolenbroek #include "dhcpd.h"
42*83ee113eSDavid van Moolenbroek #include "dst/md5.h"
43*83ee113eSDavid van Moolenbroek #include <dns/result.h>
44*83ee113eSDavid van Moolenbroek 
45*83ee113eSDavid van Moolenbroek char *ddns_standard_tag = "ddns-dhcid";
46*83ee113eSDavid van Moolenbroek char *ddns_interim_tag  = "ddns-txt";
47*83ee113eSDavid van Moolenbroek 
48*83ee113eSDavid van Moolenbroek #ifdef NSUPDATE
49*83ee113eSDavid van Moolenbroek 
50*83ee113eSDavid van Moolenbroek static void ddns_fwd_srv_connector(struct lease          *lease,
51*83ee113eSDavid van Moolenbroek 				   struct iasubopt       *lease6,
52*83ee113eSDavid van Moolenbroek 				   struct binding_scope **inscope,
53*83ee113eSDavid van Moolenbroek 				   dhcp_ddns_cb_t        *ddns_cb,
54*83ee113eSDavid van Moolenbroek 				   isc_result_t           eresult);
55*83ee113eSDavid van Moolenbroek 
56*83ee113eSDavid van Moolenbroek /* DN: No way of checking that there is enough space in a data_string's
57*83ee113eSDavid van Moolenbroek    buffer.  Be certain to allocate enough!
58*83ee113eSDavid van Moolenbroek    TL: This is why the expression evaluation code allocates a *new*
59*83ee113eSDavid van Moolenbroek    data_string.   :') */
data_string_append(struct data_string * ds1,struct data_string * ds2)60*83ee113eSDavid van Moolenbroek static void data_string_append (struct data_string *ds1,
61*83ee113eSDavid van Moolenbroek 				struct data_string *ds2)
62*83ee113eSDavid van Moolenbroek {
63*83ee113eSDavid van Moolenbroek 	memcpy (ds1 -> buffer -> data + ds1 -> len,
64*83ee113eSDavid van Moolenbroek 		ds2 -> data,
65*83ee113eSDavid van Moolenbroek 		ds2 -> len);
66*83ee113eSDavid van Moolenbroek 	ds1 -> len += ds2 -> len;
67*83ee113eSDavid van Moolenbroek }
68*83ee113eSDavid van Moolenbroek 
69*83ee113eSDavid van Moolenbroek 
70*83ee113eSDavid van Moolenbroek /* Determine what, if any, forward and reverse updates need to be
71*83ee113eSDavid van Moolenbroek  * performed, and carry them through.
72*83ee113eSDavid van Moolenbroek  */
73*83ee113eSDavid van Moolenbroek int
ddns_updates(struct packet * packet,struct lease * lease,struct lease * old,struct iasubopt * lease6,struct iasubopt * old6,struct option_state * options)74*83ee113eSDavid van Moolenbroek ddns_updates(struct packet *packet, struct lease *lease, struct lease *old,
75*83ee113eSDavid van Moolenbroek 	     struct iasubopt *lease6, struct iasubopt *old6,
76*83ee113eSDavid van Moolenbroek 	     struct option_state *options)
77*83ee113eSDavid van Moolenbroek {
78*83ee113eSDavid van Moolenbroek 	unsigned long ddns_ttl = DEFAULT_DDNS_TTL;
79*83ee113eSDavid van Moolenbroek 	struct data_string ddns_hostname;
80*83ee113eSDavid van Moolenbroek 	struct data_string ddns_domainname;
81*83ee113eSDavid van Moolenbroek 	struct data_string old_ddns_fwd_name;
82*83ee113eSDavid van Moolenbroek 	struct data_string ddns_fwd_name;
83*83ee113eSDavid van Moolenbroek 	struct data_string ddns_dhcid;
84*83ee113eSDavid van Moolenbroek 	struct binding_scope **scope = NULL;
85*83ee113eSDavid van Moolenbroek 	struct data_string d1;
86*83ee113eSDavid van Moolenbroek 	struct option_cache *oc;
87*83ee113eSDavid van Moolenbroek 	int s1, s2;
88*83ee113eSDavid van Moolenbroek 	int result = 0;
89*83ee113eSDavid van Moolenbroek 	int server_updates_a = 1;
90*83ee113eSDavid van Moolenbroek 	struct buffer *bp = (struct buffer *)0;
91*83ee113eSDavid van Moolenbroek 	int ignorep = 0, client_ignorep = 0;
92*83ee113eSDavid van Moolenbroek 	int rev_name_len;
93*83ee113eSDavid van Moolenbroek 	int i;
94*83ee113eSDavid van Moolenbroek 
95*83ee113eSDavid van Moolenbroek 	dhcp_ddns_cb_t *ddns_cb;
96*83ee113eSDavid van Moolenbroek 	int do_remove = 0;
97*83ee113eSDavid van Moolenbroek 
98*83ee113eSDavid van Moolenbroek 	if ((ddns_update_style != DDNS_UPDATE_STYLE_STANDARD) &&
99*83ee113eSDavid van Moolenbroek 	    (ddns_update_style != DDNS_UPDATE_STYLE_INTERIM))
100*83ee113eSDavid van Moolenbroek 		return (0);
101*83ee113eSDavid van Moolenbroek 
102*83ee113eSDavid van Moolenbroek 	/*
103*83ee113eSDavid van Moolenbroek 	 * sigh, I want to cancel any previous udpates before we do anything
104*83ee113eSDavid van Moolenbroek 	 * else but this means we need to deal with the lease vs lease6
105*83ee113eSDavid van Moolenbroek 	 * question twice.
106*83ee113eSDavid van Moolenbroek 	 * If there is a ddns request already outstanding cancel it.
107*83ee113eSDavid van Moolenbroek 	 */
108*83ee113eSDavid van Moolenbroek 
109*83ee113eSDavid van Moolenbroek 	if (lease != NULL) {
110*83ee113eSDavid van Moolenbroek 		if ((old != NULL) && (old->ddns_cb != NULL)) {
111*83ee113eSDavid van Moolenbroek 			ddns_cancel(old->ddns_cb, MDL);
112*83ee113eSDavid van Moolenbroek 			old->ddns_cb = NULL;
113*83ee113eSDavid van Moolenbroek 		}
114*83ee113eSDavid van Moolenbroek 	} else if (lease6 != NULL) {
115*83ee113eSDavid van Moolenbroek 		if ((old6 != NULL) && (old6->ddns_cb != NULL)) {
116*83ee113eSDavid van Moolenbroek 			ddns_cancel(old6->ddns_cb, MDL);
117*83ee113eSDavid van Moolenbroek 			old6->ddns_cb = NULL;
118*83ee113eSDavid van Moolenbroek 		}
119*83ee113eSDavid van Moolenbroek 	} else {
120*83ee113eSDavid van Moolenbroek 		log_fatal("Impossible condition at %s:%d.", MDL);
121*83ee113eSDavid van Moolenbroek 		/* Silence compiler warnings. */
122*83ee113eSDavid van Moolenbroek 		result = 0;
123*83ee113eSDavid van Moolenbroek 		return(0);
124*83ee113eSDavid van Moolenbroek 	}
125*83ee113eSDavid van Moolenbroek 
126*83ee113eSDavid van Moolenbroek 	/* allocate our control block */
127*83ee113eSDavid van Moolenbroek 	ddns_cb = ddns_cb_alloc(MDL);
128*83ee113eSDavid van Moolenbroek 	if (ddns_cb == NULL) {
129*83ee113eSDavid van Moolenbroek 		return(0);
130*83ee113eSDavid van Moolenbroek 	}
131*83ee113eSDavid van Moolenbroek 	/*
132*83ee113eSDavid van Moolenbroek 	 * Assume that we shall update both the A and ptr records and,
133*83ee113eSDavid van Moolenbroek 	 * as this is an update, set the active flag
134*83ee113eSDavid van Moolenbroek 	 */
135*83ee113eSDavid van Moolenbroek 	ddns_cb->flags = DDNS_UPDATE_ADDR | DDNS_UPDATE_PTR |
136*83ee113eSDavid van Moolenbroek 		DDNS_ACTIVE_LEASE;
137*83ee113eSDavid van Moolenbroek 
138*83ee113eSDavid van Moolenbroek 	/*
139*83ee113eSDavid van Moolenbroek 	 * For v4 we flag static leases so we don't try
140*83ee113eSDavid van Moolenbroek 	 * and manipulate the lease later.  For v6 we don't
141*83ee113eSDavid van Moolenbroek 	 * get static leases and don't need to flag them.
142*83ee113eSDavid van Moolenbroek 	 */
143*83ee113eSDavid van Moolenbroek 	if (lease != NULL) {
144*83ee113eSDavid van Moolenbroek 		scope = &(lease->scope);
145*83ee113eSDavid van Moolenbroek 		ddns_cb->address = lease->ip_addr;
146*83ee113eSDavid van Moolenbroek 		if (lease->flags & STATIC_LEASE)
147*83ee113eSDavid van Moolenbroek 			ddns_cb->flags |= DDNS_STATIC_LEASE;
148*83ee113eSDavid van Moolenbroek 	} else if (lease6 != NULL) {
149*83ee113eSDavid van Moolenbroek 		scope = &(lease6->scope);
150*83ee113eSDavid van Moolenbroek 		memcpy(ddns_cb->address.iabuf, lease6->addr.s6_addr, 16);
151*83ee113eSDavid van Moolenbroek 		ddns_cb->address.len = 16;
152*83ee113eSDavid van Moolenbroek 	}
153*83ee113eSDavid van Moolenbroek 
154*83ee113eSDavid van Moolenbroek 	memset (&d1, 0, sizeof(d1));
155*83ee113eSDavid van Moolenbroek 	memset (&ddns_hostname, 0, sizeof (ddns_hostname));
156*83ee113eSDavid van Moolenbroek 	memset (&ddns_domainname, 0, sizeof (ddns_domainname));
157*83ee113eSDavid van Moolenbroek 	memset (&old_ddns_fwd_name, 0, sizeof (ddns_fwd_name));
158*83ee113eSDavid van Moolenbroek 	memset (&ddns_fwd_name, 0, sizeof (ddns_fwd_name));
159*83ee113eSDavid van Moolenbroek 	memset (&ddns_dhcid, 0, sizeof (ddns_dhcid));
160*83ee113eSDavid van Moolenbroek 
161*83ee113eSDavid van Moolenbroek 	/* If we are allowed to accept the client's update of its own A
162*83ee113eSDavid van Moolenbroek 	   record, see if the client wants to update its own A record. */
163*83ee113eSDavid van Moolenbroek 	if (!(oc = lookup_option(&server_universe, options,
164*83ee113eSDavid van Moolenbroek 				 SV_CLIENT_UPDATES)) ||
165*83ee113eSDavid van Moolenbroek 	    evaluate_boolean_option_cache(&client_ignorep, packet, lease, NULL,
166*83ee113eSDavid van Moolenbroek 					  packet->options, options, scope,
167*83ee113eSDavid van Moolenbroek 					  oc, MDL)) {
168*83ee113eSDavid van Moolenbroek 		/* If there's no fqdn.no-client-update or if it's
169*83ee113eSDavid van Moolenbroek 		   nonzero, don't try to use the client-supplied
170*83ee113eSDavid van Moolenbroek 		   XXX */
171*83ee113eSDavid van Moolenbroek 		if (!(oc = lookup_option (&fqdn_universe, packet -> options,
172*83ee113eSDavid van Moolenbroek 					  FQDN_SERVER_UPDATE)) ||
173*83ee113eSDavid van Moolenbroek 		    evaluate_boolean_option_cache(&ignorep, packet, lease,
174*83ee113eSDavid van Moolenbroek 						  NULL, packet->options,
175*83ee113eSDavid van Moolenbroek 						  options, scope, oc, MDL))
176*83ee113eSDavid van Moolenbroek 			goto noclient;
177*83ee113eSDavid van Moolenbroek 		/* Win98 and Win2k will happily claim to be willing to
178*83ee113eSDavid van Moolenbroek 		   update an unqualified domain name. */
179*83ee113eSDavid van Moolenbroek 		if (!(oc = lookup_option (&fqdn_universe, packet -> options,
180*83ee113eSDavid van Moolenbroek 					  FQDN_DOMAINNAME)))
181*83ee113eSDavid van Moolenbroek 			goto noclient;
182*83ee113eSDavid van Moolenbroek 		if (!(oc = lookup_option (&fqdn_universe, packet -> options,
183*83ee113eSDavid van Moolenbroek 					  FQDN_FQDN)) ||
184*83ee113eSDavid van Moolenbroek 		    !evaluate_option_cache(&ddns_fwd_name, packet, lease,
185*83ee113eSDavid van Moolenbroek 					   NULL, packet->options,
186*83ee113eSDavid van Moolenbroek 					   options, scope, oc, MDL))
187*83ee113eSDavid van Moolenbroek 			goto noclient;
188*83ee113eSDavid van Moolenbroek 		ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
189*83ee113eSDavid van Moolenbroek 		server_updates_a = 0;
190*83ee113eSDavid van Moolenbroek 		goto client_updates;
191*83ee113eSDavid van Moolenbroek 	}
192*83ee113eSDavid van Moolenbroek       noclient:
193*83ee113eSDavid van Moolenbroek 	/* If do-forward-updates is disabled, this basically means don't
194*83ee113eSDavid van Moolenbroek 	   do an update unless the client is participating, so if we get
195*83ee113eSDavid van Moolenbroek 	   here and do-forward-updates is disabled, we can stop. */
196*83ee113eSDavid van Moolenbroek 	if ((oc = lookup_option (&server_universe, options,
197*83ee113eSDavid van Moolenbroek 				 SV_DO_FORWARD_UPDATES)) &&
198*83ee113eSDavid van Moolenbroek 	    !evaluate_boolean_option_cache(&ignorep, packet, lease,
199*83ee113eSDavid van Moolenbroek 					   NULL, packet->options,
200*83ee113eSDavid van Moolenbroek 					   options, scope, oc, MDL)) {
201*83ee113eSDavid van Moolenbroek 		goto out;
202*83ee113eSDavid van Moolenbroek 	}
203*83ee113eSDavid van Moolenbroek 
204*83ee113eSDavid van Moolenbroek 	/* If it's a static lease, then don't do the DNS update unless we're
205*83ee113eSDavid van Moolenbroek 	   specifically configured to do so.   If the client asked to do its
206*83ee113eSDavid van Moolenbroek 	   own update and we allowed that, we don't do this test. */
207*83ee113eSDavid van Moolenbroek 	/* XXX: note that we cannot detect static DHCPv6 leases. */
208*83ee113eSDavid van Moolenbroek 	if ((lease != NULL) && (lease->flags & STATIC_LEASE)) {
209*83ee113eSDavid van Moolenbroek 		if (!(oc = lookup_option(&server_universe, options,
210*83ee113eSDavid van Moolenbroek 					 SV_UPDATE_STATIC_LEASES)) ||
211*83ee113eSDavid van Moolenbroek 		    !evaluate_boolean_option_cache(&ignorep, packet, lease,
212*83ee113eSDavid van Moolenbroek 						   NULL, packet->options,
213*83ee113eSDavid van Moolenbroek 						   options, scope, oc, MDL))
214*83ee113eSDavid van Moolenbroek 			goto out;
215*83ee113eSDavid van Moolenbroek 	}
216*83ee113eSDavid van Moolenbroek 
217*83ee113eSDavid van Moolenbroek 	/*
218*83ee113eSDavid van Moolenbroek 	 * Compute the name for the A record.
219*83ee113eSDavid van Moolenbroek 	 */
220*83ee113eSDavid van Moolenbroek 	oc = lookup_option(&server_universe, options, SV_DDNS_HOST_NAME);
221*83ee113eSDavid van Moolenbroek 	if (oc)
222*83ee113eSDavid van Moolenbroek 		s1 = evaluate_option_cache(&ddns_hostname, packet, lease,
223*83ee113eSDavid van Moolenbroek 					   NULL, packet->options,
224*83ee113eSDavid van Moolenbroek 					   options, scope, oc, MDL);
225*83ee113eSDavid van Moolenbroek 	else
226*83ee113eSDavid van Moolenbroek 		s1 = 0;
227*83ee113eSDavid van Moolenbroek 
228*83ee113eSDavid van Moolenbroek 	oc = lookup_option(&server_universe, options, SV_DDNS_DOMAIN_NAME);
229*83ee113eSDavid van Moolenbroek 	if (oc)
230*83ee113eSDavid van Moolenbroek 		s2 = evaluate_option_cache(&ddns_domainname, packet, lease,
231*83ee113eSDavid van Moolenbroek 					   NULL, packet->options,
232*83ee113eSDavid van Moolenbroek 					   options, scope, oc, MDL);
233*83ee113eSDavid van Moolenbroek 	else
234*83ee113eSDavid van Moolenbroek 		s2 = 0;
235*83ee113eSDavid van Moolenbroek 
236*83ee113eSDavid van Moolenbroek 	if (s1 && s2) {
237*83ee113eSDavid van Moolenbroek 		if (ddns_hostname.len + ddns_domainname.len > 253) {
238*83ee113eSDavid van Moolenbroek 			log_error ("ddns_update: host.domain name too long");
239*83ee113eSDavid van Moolenbroek 
240*83ee113eSDavid van Moolenbroek 			goto out;
241*83ee113eSDavid van Moolenbroek 		}
242*83ee113eSDavid van Moolenbroek 
243*83ee113eSDavid van Moolenbroek 		buffer_allocate (&ddns_fwd_name.buffer,
244*83ee113eSDavid van Moolenbroek 				 ddns_hostname.len + ddns_domainname.len + 2,
245*83ee113eSDavid van Moolenbroek 				 MDL);
246*83ee113eSDavid van Moolenbroek 		if (ddns_fwd_name.buffer) {
247*83ee113eSDavid van Moolenbroek 			ddns_fwd_name.data = ddns_fwd_name.buffer->data;
248*83ee113eSDavid van Moolenbroek 			data_string_append (&ddns_fwd_name, &ddns_hostname);
249*83ee113eSDavid van Moolenbroek 			ddns_fwd_name.buffer->data[ddns_fwd_name.len] = '.';
250*83ee113eSDavid van Moolenbroek 			ddns_fwd_name.len++;
251*83ee113eSDavid van Moolenbroek 			data_string_append (&ddns_fwd_name, &ddns_domainname);
252*83ee113eSDavid van Moolenbroek 			ddns_fwd_name.buffer->data[ddns_fwd_name.len] ='\0';
253*83ee113eSDavid van Moolenbroek 			ddns_fwd_name.terminated = 1;
254*83ee113eSDavid van Moolenbroek 		}
255*83ee113eSDavid van Moolenbroek 	}
256*83ee113eSDavid van Moolenbroek       client_updates:
257*83ee113eSDavid van Moolenbroek 
258*83ee113eSDavid van Moolenbroek 	/* See if there's a name already stored on the lease. */
259*83ee113eSDavid van Moolenbroek 	if (find_bound_string(&old_ddns_fwd_name, *scope, "ddns-fwd-name")) {
260*83ee113eSDavid van Moolenbroek 		/* If there is, see if it's different. */
261*83ee113eSDavid van Moolenbroek 		if (old_ddns_fwd_name.len != ddns_fwd_name.len ||
262*83ee113eSDavid van Moolenbroek 		    memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data,
263*83ee113eSDavid van Moolenbroek 			    old_ddns_fwd_name.len)) {
264*83ee113eSDavid van Moolenbroek 			/*
265*83ee113eSDavid van Moolenbroek 			 * If the name is different, mark the old record
266*83ee113eSDavid van Moolenbroek 			 * for deletion and continue getting the new info.
267*83ee113eSDavid van Moolenbroek 			 */
268*83ee113eSDavid van Moolenbroek 			do_remove = 1;
269*83ee113eSDavid van Moolenbroek 			goto in;
270*83ee113eSDavid van Moolenbroek 		}
271*83ee113eSDavid van Moolenbroek 
272*83ee113eSDavid van Moolenbroek #if defined  (DDNS_UPDATE_SLOW_TRANSITION)
273*83ee113eSDavid van Moolenbroek 		/*
274*83ee113eSDavid van Moolenbroek 		 * If the slow transition code is enabled check to see
275*83ee113eSDavid van Moolenbroek 		 * if the stored type (standard or interim doesn't
276*83ee113eSDavid van Moolenbroek 		 * match the type currently in use.  If it doesn't
277*83ee113eSDavid van Moolenbroek 		 * try to remove and replace the DNS record
278*83ee113eSDavid van Moolenbroek 		 */
279*83ee113eSDavid van Moolenbroek 		if (((ddns_update_style == DDNS_UPDATE_STYLE_STANDARD) &&
280*83ee113eSDavid van Moolenbroek 		     find_bound_string(&ddns_dhcid, *scope, ddns_interim_tag)) ||
281*83ee113eSDavid van Moolenbroek 		    ((ddns_update_style == DDNS_UPDATE_STYLE_INTERIM) &&
282*83ee113eSDavid van Moolenbroek 		     find_bound_string(&ddns_dhcid, *scope, ddns_standard_tag))) {
283*83ee113eSDavid van Moolenbroek 			data_string_forget(&ddns_dhcid, MDL);
284*83ee113eSDavid van Moolenbroek 			do_remove = 1;
285*83ee113eSDavid van Moolenbroek 			goto in;
286*83ee113eSDavid van Moolenbroek 		}
287*83ee113eSDavid van Moolenbroek #endif
288*83ee113eSDavid van Moolenbroek 
289*83ee113eSDavid van Moolenbroek 		/* See if the administrator wants to do updates even
290*83ee113eSDavid van Moolenbroek 		   in cases where the update already appears to have been
291*83ee113eSDavid van Moolenbroek 		   done. */
292*83ee113eSDavid van Moolenbroek 		if (!(oc = lookup_option(&server_universe, options,
293*83ee113eSDavid van Moolenbroek 					 SV_UPDATE_OPTIMIZATION)) ||
294*83ee113eSDavid van Moolenbroek 		    evaluate_boolean_option_cache(&ignorep, packet, lease,
295*83ee113eSDavid van Moolenbroek 						  NULL, packet->options,
296*83ee113eSDavid van Moolenbroek 						  options, scope, oc, MDL)) {
297*83ee113eSDavid van Moolenbroek 			result = 1;
298*83ee113eSDavid van Moolenbroek 			goto noerror;
299*83ee113eSDavid van Moolenbroek 		}
300*83ee113eSDavid van Moolenbroek 	/* If there's no "ddns-fwd-name" on the lease record, see if
301*83ee113eSDavid van Moolenbroek 	 * there's a ddns-client-fqdn indicating a previous client
302*83ee113eSDavid van Moolenbroek 	 * update (if it changes, we need to adjust the PTR).
303*83ee113eSDavid van Moolenbroek 	 */
304*83ee113eSDavid van Moolenbroek 	} else if (find_bound_string(&old_ddns_fwd_name, *scope,
305*83ee113eSDavid van Moolenbroek 				     "ddns-client-fqdn")) {
306*83ee113eSDavid van Moolenbroek 		/* If the name is not different, no need to update
307*83ee113eSDavid van Moolenbroek 		   the PTR record. */
308*83ee113eSDavid van Moolenbroek 		if (old_ddns_fwd_name.len == ddns_fwd_name.len &&
309*83ee113eSDavid van Moolenbroek 		    !memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data,
310*83ee113eSDavid van Moolenbroek 			     old_ddns_fwd_name.len) &&
311*83ee113eSDavid van Moolenbroek 		    (!(oc = lookup_option(&server_universe, options,
312*83ee113eSDavid van Moolenbroek 					  SV_UPDATE_OPTIMIZATION)) ||
313*83ee113eSDavid van Moolenbroek 		     evaluate_boolean_option_cache(&ignorep, packet, lease,
314*83ee113eSDavid van Moolenbroek 						   NULL, packet->options,
315*83ee113eSDavid van Moolenbroek 						   options, scope, oc, MDL))) {
316*83ee113eSDavid van Moolenbroek 			goto noerror;
317*83ee113eSDavid van Moolenbroek 		}
318*83ee113eSDavid van Moolenbroek 	}
319*83ee113eSDavid van Moolenbroek       in:
320*83ee113eSDavid van Moolenbroek 
321*83ee113eSDavid van Moolenbroek 	/* If we don't have a name that the client has been assigned, we
322*83ee113eSDavid van Moolenbroek 	   can just skip all this. */
323*83ee113eSDavid van Moolenbroek 
324*83ee113eSDavid van Moolenbroek 	if ((!ddns_fwd_name.len) || (ddns_fwd_name.len > 255)) {
325*83ee113eSDavid van Moolenbroek 		if (ddns_fwd_name.len > 255) {
326*83ee113eSDavid van Moolenbroek 			log_error ("client provided fqdn: too long");
327*83ee113eSDavid van Moolenbroek 		}
328*83ee113eSDavid van Moolenbroek 
329*83ee113eSDavid van Moolenbroek 		/* If desired do the removals */
330*83ee113eSDavid van Moolenbroek 		if (do_remove != 0) {
331*83ee113eSDavid van Moolenbroek 			(void) ddns_removals(lease, lease6, NULL, ISC_TRUE);
332*83ee113eSDavid van Moolenbroek 		}
333*83ee113eSDavid van Moolenbroek 		goto out;
334*83ee113eSDavid van Moolenbroek 	}
335*83ee113eSDavid van Moolenbroek 
336*83ee113eSDavid van Moolenbroek 	/*
337*83ee113eSDavid van Moolenbroek 	 * Compute the RR TTL.
338*83ee113eSDavid van Moolenbroek 	 *
339*83ee113eSDavid van Moolenbroek 	 * We have two ways of computing the TTL.
340*83ee113eSDavid van Moolenbroek 	 * The old behavior was to allow for the customer to set up
341*83ee113eSDavid van Moolenbroek 	 * the option or to default things.  For v4 this was 1/2
342*83ee113eSDavid van Moolenbroek 	 * of the lease time, for v6 this was DEFAULT_DDNS_TTL.
343*83ee113eSDavid van Moolenbroek 	 * The new behavior continues to allow the customer to set
344*83ee113eSDavid van Moolenbroek 	 * up an option but the defaults are a little different.
345*83ee113eSDavid van Moolenbroek 	 * We now use 1/2 of the (preferred) lease time for both
346*83ee113eSDavid van Moolenbroek 	 * v4 and v6 and cap them at a maximum value.
347*83ee113eSDavid van Moolenbroek 	 * If the customer chooses to use an experession that references
348*83ee113eSDavid van Moolenbroek 	 * part of the lease the v6 value will be the default as there
349*83ee113eSDavid van Moolenbroek 	 * isn't a lease available for v6.
350*83ee113eSDavid van Moolenbroek 	 */
351*83ee113eSDavid van Moolenbroek 
352*83ee113eSDavid van Moolenbroek 	ddns_ttl = DEFAULT_DDNS_TTL;
353*83ee113eSDavid van Moolenbroek 	if (lease != NULL) {
354*83ee113eSDavid van Moolenbroek 		if (lease->ends <= cur_time) {
355*83ee113eSDavid van Moolenbroek 			ddns_ttl = 0;
356*83ee113eSDavid van Moolenbroek 		} else {
357*83ee113eSDavid van Moolenbroek 			ddns_ttl = (lease->ends - cur_time)/2;
358*83ee113eSDavid van Moolenbroek 		}
359*83ee113eSDavid van Moolenbroek 	}
360*83ee113eSDavid van Moolenbroek #ifndef USE_OLD_DDNS_TTL
361*83ee113eSDavid van Moolenbroek 	else if (lease6 != NULL) {
362*83ee113eSDavid van Moolenbroek 		ddns_ttl = lease6->prefer/2;
363*83ee113eSDavid van Moolenbroek 	}
364*83ee113eSDavid van Moolenbroek 
365*83ee113eSDavid van Moolenbroek 	if (ddns_ttl > MAX_DEFAULT_DDNS_TTL) {
366*83ee113eSDavid van Moolenbroek 		ddns_ttl = MAX_DEFAULT_DDNS_TTL;
367*83ee113eSDavid van Moolenbroek 	}
368*83ee113eSDavid van Moolenbroek #endif
369*83ee113eSDavid van Moolenbroek 
370*83ee113eSDavid van Moolenbroek 	if ((oc = lookup_option(&server_universe, options, SV_DDNS_TTL))) {
371*83ee113eSDavid van Moolenbroek 		if (evaluate_option_cache(&d1, packet, lease, NULL,
372*83ee113eSDavid van Moolenbroek 					  packet->options, options,
373*83ee113eSDavid van Moolenbroek 					  scope, oc, MDL)) {
374*83ee113eSDavid van Moolenbroek 			if (d1.len == sizeof (u_int32_t))
375*83ee113eSDavid van Moolenbroek 				ddns_ttl = getULong (d1.data);
376*83ee113eSDavid van Moolenbroek 			data_string_forget (&d1, MDL);
377*83ee113eSDavid van Moolenbroek 		}
378*83ee113eSDavid van Moolenbroek 	}
379*83ee113eSDavid van Moolenbroek 
380*83ee113eSDavid van Moolenbroek 	ddns_cb->ttl = ddns_ttl;
381*83ee113eSDavid van Moolenbroek 
382*83ee113eSDavid van Moolenbroek 	/*
383*83ee113eSDavid van Moolenbroek 	 * Compute the reverse IP name, starting with the domain name.
384*83ee113eSDavid van Moolenbroek 	 */
385*83ee113eSDavid van Moolenbroek 	oc = lookup_option(&server_universe, options, SV_DDNS_REV_DOMAIN_NAME);
386*83ee113eSDavid van Moolenbroek 	if (oc)
387*83ee113eSDavid van Moolenbroek 		s1 = evaluate_option_cache(&d1, packet, lease, NULL,
388*83ee113eSDavid van Moolenbroek 					   packet->options, options,
389*83ee113eSDavid van Moolenbroek 					   scope, oc, MDL);
390*83ee113eSDavid van Moolenbroek 	else
391*83ee113eSDavid van Moolenbroek 		s1 = 0;
392*83ee113eSDavid van Moolenbroek 
393*83ee113eSDavid van Moolenbroek 	/*
394*83ee113eSDavid van Moolenbroek 	 * Figure out the length of the part of the name that depends
395*83ee113eSDavid van Moolenbroek 	 * on the address.
396*83ee113eSDavid van Moolenbroek 	 */
397*83ee113eSDavid van Moolenbroek 	if (ddns_cb->address.len == 4) {
398*83ee113eSDavid van Moolenbroek 		char buf[17];
399*83ee113eSDavid van Moolenbroek 		/* XXX: WOW this is gross. */
400*83ee113eSDavid van Moolenbroek 		rev_name_len = snprintf(buf, sizeof(buf), "%u.%u.%u.%u.",
401*83ee113eSDavid van Moolenbroek 					ddns_cb->address.iabuf[3] & 0xff,
402*83ee113eSDavid van Moolenbroek 					ddns_cb->address.iabuf[2] & 0xff,
403*83ee113eSDavid van Moolenbroek 					ddns_cb->address.iabuf[1] & 0xff,
404*83ee113eSDavid van Moolenbroek 					ddns_cb->address.iabuf[0] & 0xff) + 1;
405*83ee113eSDavid van Moolenbroek 
406*83ee113eSDavid van Moolenbroek 		if (s1) {
407*83ee113eSDavid van Moolenbroek 			rev_name_len += d1.len;
408*83ee113eSDavid van Moolenbroek 
409*83ee113eSDavid van Moolenbroek 			if (rev_name_len > 255) {
410*83ee113eSDavid van Moolenbroek 				log_error("ddns_update: Calculated rev domain "
411*83ee113eSDavid van Moolenbroek 					  "name too long.");
412*83ee113eSDavid van Moolenbroek 				s1 = 0;
413*83ee113eSDavid van Moolenbroek 				data_string_forget(&d1, MDL);
414*83ee113eSDavid van Moolenbroek 			}
415*83ee113eSDavid van Moolenbroek 		}
416*83ee113eSDavid van Moolenbroek 	} else if (ddns_cb->address.len == 16) {
417*83ee113eSDavid van Moolenbroek 		/*
418*83ee113eSDavid van Moolenbroek 		 * IPv6 reverse names are always the same length, with
419*83ee113eSDavid van Moolenbroek 		 * 32 hex characters separated by dots.
420*83ee113eSDavid van Moolenbroek 		 */
421*83ee113eSDavid van Moolenbroek 		rev_name_len = sizeof("0.1.2.3.4.5.6.7."
422*83ee113eSDavid van Moolenbroek 				      "8.9.a.b.c.d.e.f."
423*83ee113eSDavid van Moolenbroek 				      "0.1.2.3.4.5.6.7."
424*83ee113eSDavid van Moolenbroek 				      "8.9.a.b.c.d.e.f."
425*83ee113eSDavid van Moolenbroek 				      "ip6.arpa.");
426*83ee113eSDavid van Moolenbroek 
427*83ee113eSDavid van Moolenbroek 		/* Set s1 to make sure we gate into updates. */
428*83ee113eSDavid van Moolenbroek 		s1 = 1;
429*83ee113eSDavid van Moolenbroek 	} else {
430*83ee113eSDavid van Moolenbroek 		log_fatal("invalid address length %d", ddns_cb->address.len);
431*83ee113eSDavid van Moolenbroek 		/* Silence compiler warnings. */
432*83ee113eSDavid van Moolenbroek 		return 0;
433*83ee113eSDavid van Moolenbroek 	}
434*83ee113eSDavid van Moolenbroek 
435*83ee113eSDavid van Moolenbroek 	/* See if we are configured NOT to do reverse ptr updates */
436*83ee113eSDavid van Moolenbroek 	if ((oc = lookup_option(&server_universe, options,
437*83ee113eSDavid van Moolenbroek 				SV_DO_REVERSE_UPDATES)) &&
438*83ee113eSDavid van Moolenbroek 	    !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL,
439*83ee113eSDavid van Moolenbroek 					   packet->options, options,
440*83ee113eSDavid van Moolenbroek 					   scope, oc, MDL)) {
441*83ee113eSDavid van Moolenbroek 		ddns_cb->flags &= ~DDNS_UPDATE_PTR;
442*83ee113eSDavid van Moolenbroek 	}
443*83ee113eSDavid van Moolenbroek 
444*83ee113eSDavid van Moolenbroek 	if (s1) {
445*83ee113eSDavid van Moolenbroek 		buffer_allocate(&ddns_cb->rev_name.buffer, rev_name_len, MDL);
446*83ee113eSDavid van Moolenbroek 		if (ddns_cb->rev_name.buffer != NULL) {
447*83ee113eSDavid van Moolenbroek 			struct data_string *rname = &ddns_cb->rev_name;
448*83ee113eSDavid van Moolenbroek 			rname->data = rname->buffer->data;
449*83ee113eSDavid van Moolenbroek 
450*83ee113eSDavid van Moolenbroek 			if (ddns_cb->address.len == 4) {
451*83ee113eSDavid van Moolenbroek 				rname->len =
452*83ee113eSDavid van Moolenbroek 				    sprintf((char *)rname->buffer->data,
453*83ee113eSDavid van Moolenbroek 					    "%u.%u.%u.%u.",
454*83ee113eSDavid van Moolenbroek 					    ddns_cb->address.iabuf[3] & 0xff,
455*83ee113eSDavid van Moolenbroek 					    ddns_cb->address.iabuf[2] & 0xff,
456*83ee113eSDavid van Moolenbroek 					    ddns_cb->address.iabuf[1] & 0xff,
457*83ee113eSDavid van Moolenbroek 					    ddns_cb->address.iabuf[0] & 0xff);
458*83ee113eSDavid van Moolenbroek 
459*83ee113eSDavid van Moolenbroek 				/*
460*83ee113eSDavid van Moolenbroek 				 * d1.data may be opaque, garbage bytes, from
461*83ee113eSDavid van Moolenbroek 				 * user (mis)configuration.
462*83ee113eSDavid van Moolenbroek 				 */
463*83ee113eSDavid van Moolenbroek 				data_string_append(rname, &d1);
464*83ee113eSDavid van Moolenbroek 				rname->buffer->data[rname->len] = '\0';
465*83ee113eSDavid van Moolenbroek 			} else if (ddns_cb->address.len == 16) {
466*83ee113eSDavid van Moolenbroek 				char *p = (char *)&rname->buffer->data;
467*83ee113eSDavid van Moolenbroek 				unsigned char *a = ddns_cb->address.iabuf + 15;
468*83ee113eSDavid van Moolenbroek 				for (i=0; i<16; i++) {
469*83ee113eSDavid van Moolenbroek 					sprintf(p, "%x.%x.",
470*83ee113eSDavid van Moolenbroek 						(*a & 0xF), ((*a >> 4) & 0xF));
471*83ee113eSDavid van Moolenbroek 					p += 4;
472*83ee113eSDavid van Moolenbroek 					a -= 1;
473*83ee113eSDavid van Moolenbroek 				}
474*83ee113eSDavid van Moolenbroek 				strcat(p, "ip6.arpa.");
475*83ee113eSDavid van Moolenbroek 				rname->len = strlen((const char *)rname->data);
476*83ee113eSDavid van Moolenbroek 			}
477*83ee113eSDavid van Moolenbroek 
478*83ee113eSDavid van Moolenbroek 			rname->terminated = 1;
479*83ee113eSDavid van Moolenbroek 		}
480*83ee113eSDavid van Moolenbroek 
481*83ee113eSDavid van Moolenbroek 		if (d1.data != NULL)
482*83ee113eSDavid van Moolenbroek 			data_string_forget(&d1, MDL);
483*83ee113eSDavid van Moolenbroek 	}
484*83ee113eSDavid van Moolenbroek 
485*83ee113eSDavid van Moolenbroek 	/*
486*83ee113eSDavid van Moolenbroek 	 * copy the string now so we can pass it to the dhcid routines
487*83ee113eSDavid van Moolenbroek 	 * via the ddns_cb pointer
488*83ee113eSDavid van Moolenbroek 	 */
489*83ee113eSDavid van Moolenbroek 	data_string_copy(&ddns_cb->fwd_name, &ddns_fwd_name, MDL);
490*83ee113eSDavid van Moolenbroek 
491*83ee113eSDavid van Moolenbroek 	/*
492*83ee113eSDavid van Moolenbroek 	 * If we are updating the A record, compute the DHCID value.
493*83ee113eSDavid van Moolenbroek 	 * We have two options for computing the DHCID value, the older
494*83ee113eSDavid van Moolenbroek 	 * interim version and the newer standard version.  The interim
495*83ee113eSDavid van Moolenbroek 	 * has some issues but is left as is to avoid compatibility issues.
496*83ee113eSDavid van Moolenbroek 	 *
497*83ee113eSDavid van Moolenbroek 	 * We select the type of DHCID to construct and the information to
498*83ee113eSDavid van Moolenbroek 	 * use for the digest based on 4701 section 3.3
499*83ee113eSDavid van Moolenbroek 	 */
500*83ee113eSDavid van Moolenbroek 	if ((ddns_cb->flags & DDNS_UPDATE_ADDR) != 0) {
501*83ee113eSDavid van Moolenbroek 		int ddns_type;
502*83ee113eSDavid van Moolenbroek 		int ddns_len;
503*83ee113eSDavid van Moolenbroek 		if (ddns_update_style == DDNS_UPDATE_STYLE_STANDARD) {
504*83ee113eSDavid van Moolenbroek 			/* The standard style */
505*83ee113eSDavid van Moolenbroek 			ddns_cb->lease_tag = ddns_standard_tag;
506*83ee113eSDavid van Moolenbroek 			ddns_cb->dhcid_class = dns_rdatatype_dhcid;
507*83ee113eSDavid van Moolenbroek 			ddns_type = 1;
508*83ee113eSDavid van Moolenbroek 			ddns_len = 4;
509*83ee113eSDavid van Moolenbroek 		} else {
510*83ee113eSDavid van Moolenbroek 			/* The older interim style */
511*83ee113eSDavid van Moolenbroek 			ddns_cb->lease_tag = ddns_interim_tag;
512*83ee113eSDavid van Moolenbroek 			ddns_cb->dhcid_class = dns_rdatatype_txt;
513*83ee113eSDavid van Moolenbroek 			/* for backwards compatibility */
514*83ee113eSDavid van Moolenbroek 			ddns_type = DHO_DHCP_CLIENT_IDENTIFIER;
515*83ee113eSDavid van Moolenbroek 			/* IAID incorrectly included */
516*83ee113eSDavid van Moolenbroek 			ddns_len = 0;
517*83ee113eSDavid van Moolenbroek 		}
518*83ee113eSDavid van Moolenbroek 
519*83ee113eSDavid van Moolenbroek 
520*83ee113eSDavid van Moolenbroek 		if (lease6 != NULL) {
521*83ee113eSDavid van Moolenbroek 			if (lease6->ia->iaid_duid.len < ddns_len)
522*83ee113eSDavid van Moolenbroek 				goto badfqdn;
523*83ee113eSDavid van Moolenbroek 			result = get_dhcid(ddns_cb, 2,
524*83ee113eSDavid van Moolenbroek 					   lease6->ia->iaid_duid.data + ddns_len,
525*83ee113eSDavid van Moolenbroek 					   lease6->ia->iaid_duid.len - ddns_len);
526*83ee113eSDavid van Moolenbroek 		} else if ((lease != NULL) &&
527*83ee113eSDavid van Moolenbroek 			   (lease->uid != NULL) &&
528*83ee113eSDavid van Moolenbroek 			   (lease->uid_len != 0)) {
529*83ee113eSDavid van Moolenbroek 			/* If this is standard check for an RFC 4361
530*83ee113eSDavid van Moolenbroek 			 * compliant client identifier
531*83ee113eSDavid van Moolenbroek 			 */
532*83ee113eSDavid van Moolenbroek 			if ((ddns_update_style == DDNS_UPDATE_STYLE_STANDARD) &&
533*83ee113eSDavid van Moolenbroek 			    (lease->uid[0] == 255)) {
534*83ee113eSDavid van Moolenbroek 				if (lease->uid_len < 5)
535*83ee113eSDavid van Moolenbroek 					goto badfqdn;
536*83ee113eSDavid van Moolenbroek 				result = get_dhcid(ddns_cb, 2,
537*83ee113eSDavid van Moolenbroek 						   lease->uid + 5,
538*83ee113eSDavid van Moolenbroek 						   lease->uid_len - 5);
539*83ee113eSDavid van Moolenbroek 			} else {
540*83ee113eSDavid van Moolenbroek 				result = get_dhcid(ddns_cb, ddns_type,
541*83ee113eSDavid van Moolenbroek 						   lease->uid,
542*83ee113eSDavid van Moolenbroek 						   lease->uid_len);
543*83ee113eSDavid van Moolenbroek 			}
544*83ee113eSDavid van Moolenbroek 		} else if (lease != NULL)
545*83ee113eSDavid van Moolenbroek 			result = get_dhcid(ddns_cb, 0,
546*83ee113eSDavid van Moolenbroek 					   lease->hardware_addr.hbuf,
547*83ee113eSDavid van Moolenbroek 					   lease->hardware_addr.hlen);
548*83ee113eSDavid van Moolenbroek 		else
549*83ee113eSDavid van Moolenbroek 			log_fatal("Impossible condition at %s:%d.", MDL);
550*83ee113eSDavid van Moolenbroek 
551*83ee113eSDavid van Moolenbroek 		if (!result)
552*83ee113eSDavid van Moolenbroek 			goto badfqdn;
553*83ee113eSDavid van Moolenbroek 	}
554*83ee113eSDavid van Moolenbroek 
555*83ee113eSDavid van Moolenbroek 	/*
556*83ee113eSDavid van Moolenbroek 	 * Perform updates.
557*83ee113eSDavid van Moolenbroek 	 */
558*83ee113eSDavid van Moolenbroek 
559*83ee113eSDavid van Moolenbroek 	if (ddns_cb->flags & DDNS_UPDATE_ADDR) {
560*83ee113eSDavid van Moolenbroek 		oc = lookup_option(&server_universe, options,
561*83ee113eSDavid van Moolenbroek 				   SV_DDNS_CONFLICT_DETECT);
562*83ee113eSDavid van Moolenbroek 		if (oc &&
563*83ee113eSDavid van Moolenbroek 		    !evaluate_boolean_option_cache(&ignorep, packet, lease,
564*83ee113eSDavid van Moolenbroek 						   NULL, packet->options,
565*83ee113eSDavid van Moolenbroek 						   options, scope, oc, MDL))
566*83ee113eSDavid van Moolenbroek 			ddns_cb->flags |= DDNS_CONFLICT_OVERRIDE;
567*83ee113eSDavid van Moolenbroek 
568*83ee113eSDavid van Moolenbroek 	}
569*83ee113eSDavid van Moolenbroek 
570*83ee113eSDavid van Moolenbroek 	/*
571*83ee113eSDavid van Moolenbroek 	 * Previously if we failed during the removal operations
572*83ee113eSDavid van Moolenbroek 	 * we skipped the fqdn option processing.  I'm not sure
573*83ee113eSDavid van Moolenbroek 	 * if we want to continue with that if we fail before sending
574*83ee113eSDavid van Moolenbroek 	 * the ddns messages.  Currently we don't.
575*83ee113eSDavid van Moolenbroek 	 */
576*83ee113eSDavid van Moolenbroek 	if (do_remove) {
577*83ee113eSDavid van Moolenbroek 		/*
578*83ee113eSDavid van Moolenbroek 		 * We should log a more specific error closer to the actual
579*83ee113eSDavid van Moolenbroek 		 * error if we want one. ddns_removal failure not logged here.
580*83ee113eSDavid van Moolenbroek 		 */
581*83ee113eSDavid van Moolenbroek 		 (void) ddns_removals(lease, lease6, ddns_cb, ISC_TRUE);
582*83ee113eSDavid van Moolenbroek 	}
583*83ee113eSDavid van Moolenbroek 	else {
584*83ee113eSDavid van Moolenbroek 		ddns_fwd_srv_connector(lease, lease6, scope, ddns_cb,
585*83ee113eSDavid van Moolenbroek 				       ISC_R_SUCCESS);
586*83ee113eSDavid van Moolenbroek 	}
587*83ee113eSDavid van Moolenbroek 	ddns_cb = NULL;
588*83ee113eSDavid van Moolenbroek 
589*83ee113eSDavid van Moolenbroek       noerror:
590*83ee113eSDavid van Moolenbroek 	/*
591*83ee113eSDavid van Moolenbroek 	 * If fqdn-reply option is disabled in dhcpd.conf, then don't
592*83ee113eSDavid van Moolenbroek 	 * send the client an FQDN option at all, even if one was requested.
593*83ee113eSDavid van Moolenbroek 	 * (WinXP clients allegedly misbehave if the option is present,
594*83ee113eSDavid van Moolenbroek 	 * refusing to handle PTR updates themselves).
595*83ee113eSDavid van Moolenbroek 	 */
596*83ee113eSDavid van Moolenbroek 	if ((oc = lookup_option (&server_universe, options, SV_FQDN_REPLY)) &&
597*83ee113eSDavid van Moolenbroek   	    !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL,
598*83ee113eSDavid van Moolenbroek   					   packet->options, options,
599*83ee113eSDavid van Moolenbroek   					   scope, oc, MDL)) {
600*83ee113eSDavid van Moolenbroek   	    	goto badfqdn;
601*83ee113eSDavid van Moolenbroek 
602*83ee113eSDavid van Moolenbroek 	/* If we're ignoring client updates, then we tell a sort of 'white
603*83ee113eSDavid van Moolenbroek 	 * lie'.  We've already updated the name the server wants (per the
604*83ee113eSDavid van Moolenbroek 	 * config written by the server admin).  Now let the client do as
605*83ee113eSDavid van Moolenbroek 	 * it pleases with the name they supplied (if any).
606*83ee113eSDavid van Moolenbroek 	 *
607*83ee113eSDavid van Moolenbroek 	 * We only form an FQDN option this way if the client supplied an
608*83ee113eSDavid van Moolenbroek 	 * FQDN option that had FQDN_SERVER_UPDATE set false.
609*83ee113eSDavid van Moolenbroek 	 */
610*83ee113eSDavid van Moolenbroek 	} else if (client_ignorep &&
611*83ee113eSDavid van Moolenbroek 	    (oc = lookup_option(&fqdn_universe, packet->options,
612*83ee113eSDavid van Moolenbroek 				FQDN_SERVER_UPDATE)) &&
613*83ee113eSDavid van Moolenbroek 	    !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL,
614*83ee113eSDavid van Moolenbroek 					   packet->options, options,
615*83ee113eSDavid van Moolenbroek 					   scope, oc, MDL)) {
616*83ee113eSDavid van Moolenbroek 		oc = lookup_option(&fqdn_universe, packet->options, FQDN_FQDN);
617*83ee113eSDavid van Moolenbroek 		if (oc && evaluate_option_cache(&d1, packet, lease, NULL,
618*83ee113eSDavid van Moolenbroek 						packet->options, options,
619*83ee113eSDavid van Moolenbroek 						scope, oc, MDL)) {
620*83ee113eSDavid van Moolenbroek 			if (d1.len == 0 ||
621*83ee113eSDavid van Moolenbroek 			    !buffer_allocate(&bp, d1.len + 5, MDL))
622*83ee113eSDavid van Moolenbroek 				goto badfqdn;
623*83ee113eSDavid van Moolenbroek 
624*83ee113eSDavid van Moolenbroek 			/* Server pretends it is not updating. */
625*83ee113eSDavid van Moolenbroek 			bp->data[0] = 0;
626*83ee113eSDavid van Moolenbroek 			if (!save_option_buffer(&fqdn_universe, options,
627*83ee113eSDavid van Moolenbroek 						bp, &bp->data[0], 1,
628*83ee113eSDavid van Moolenbroek 						FQDN_SERVER_UPDATE, 0))
629*83ee113eSDavid van Moolenbroek 				goto badfqdn;
630*83ee113eSDavid van Moolenbroek 
631*83ee113eSDavid van Moolenbroek 			/* Client is encouraged to update. */
632*83ee113eSDavid van Moolenbroek 			bp->data[1] = 0;
633*83ee113eSDavid van Moolenbroek 			if (!save_option_buffer(&fqdn_universe, options,
634*83ee113eSDavid van Moolenbroek 						bp, &bp->data[1], 1,
635*83ee113eSDavid van Moolenbroek 						FQDN_NO_CLIENT_UPDATE, 0))
636*83ee113eSDavid van Moolenbroek 				goto badfqdn;
637*83ee113eSDavid van Moolenbroek 
638*83ee113eSDavid van Moolenbroek 			/* Use the encoding of client's FQDN option. */
639*83ee113eSDavid van Moolenbroek 			oc = lookup_option(&fqdn_universe, packet->options,
640*83ee113eSDavid van Moolenbroek 					   FQDN_ENCODED);
641*83ee113eSDavid van Moolenbroek 			if (oc &&
642*83ee113eSDavid van Moolenbroek 			    evaluate_boolean_option_cache(&ignorep, packet,
643*83ee113eSDavid van Moolenbroek 							  lease, NULL,
644*83ee113eSDavid van Moolenbroek 							  packet->options,
645*83ee113eSDavid van Moolenbroek 							  options, scope,
646*83ee113eSDavid van Moolenbroek 							  oc, MDL))
647*83ee113eSDavid van Moolenbroek 				bp->data[2] = 1; /* FQDN is encoded. */
648*83ee113eSDavid van Moolenbroek 			else
649*83ee113eSDavid van Moolenbroek 				bp->data[2] = 0; /* FQDN is not encoded. */
650*83ee113eSDavid van Moolenbroek 
651*83ee113eSDavid van Moolenbroek 			if (!save_option_buffer(&fqdn_universe, options,
652*83ee113eSDavid van Moolenbroek 						bp, &bp->data[2], 1,
653*83ee113eSDavid van Moolenbroek 						FQDN_ENCODED, 0))
654*83ee113eSDavid van Moolenbroek 				goto badfqdn;
655*83ee113eSDavid van Moolenbroek 
656*83ee113eSDavid van Moolenbroek 			/* Current FQDN drafts indicate 255 is mandatory. */
657*83ee113eSDavid van Moolenbroek 			bp->data[3] = 255;
658*83ee113eSDavid van Moolenbroek 			if (!save_option_buffer(&fqdn_universe, options,
659*83ee113eSDavid van Moolenbroek 						bp, &bp->data[3], 1,
660*83ee113eSDavid van Moolenbroek 						FQDN_RCODE1, 0))
661*83ee113eSDavid van Moolenbroek 				goto badfqdn;
662*83ee113eSDavid van Moolenbroek 
663*83ee113eSDavid van Moolenbroek 			bp->data[4] = 255;
664*83ee113eSDavid van Moolenbroek 			if (!save_option_buffer(&fqdn_universe, options,
665*83ee113eSDavid van Moolenbroek 						bp, &bp->data[4], 1,
666*83ee113eSDavid van Moolenbroek 						FQDN_RCODE2, 0))
667*83ee113eSDavid van Moolenbroek 				goto badfqdn;
668*83ee113eSDavid van Moolenbroek 
669*83ee113eSDavid van Moolenbroek 			/* Copy in the FQDN supplied by the client.  Note well
670*83ee113eSDavid van Moolenbroek 			 * that the format of this option in the cache is going
671*83ee113eSDavid van Moolenbroek 			 * to be in text format.  If the fqdn supplied by the
672*83ee113eSDavid van Moolenbroek 			 * client is encoded, it is decoded into the option
673*83ee113eSDavid van Moolenbroek 			 * cache when parsed out of the packet.  It will be
674*83ee113eSDavid van Moolenbroek 			 * re-encoded when the option is assembled to be
675*83ee113eSDavid van Moolenbroek 			 * transmitted if the client elects that encoding.
676*83ee113eSDavid van Moolenbroek 			 */
677*83ee113eSDavid van Moolenbroek 			memcpy(&bp->data[5], d1.data, d1.len);
678*83ee113eSDavid van Moolenbroek 			if (!save_option_buffer(&fqdn_universe, options,
679*83ee113eSDavid van Moolenbroek 						bp, &bp->data[5], d1.len,
680*83ee113eSDavid van Moolenbroek 						FQDN_FQDN, 0))
681*83ee113eSDavid van Moolenbroek 				goto badfqdn;
682*83ee113eSDavid van Moolenbroek 
683*83ee113eSDavid van Moolenbroek 			data_string_forget(&d1, MDL);
684*83ee113eSDavid van Moolenbroek 		}
685*83ee113eSDavid van Moolenbroek 	/* Set up the outgoing FQDN option if there was an incoming
686*83ee113eSDavid van Moolenbroek 	 * FQDN option.  If there's a valid FQDN option, there MUST
687*83ee113eSDavid van Moolenbroek 	 * be an FQDN_SERVER_UPDATES suboption, it's part of the fixed
688*83ee113eSDavid van Moolenbroek 	 * length head of the option contents, so we test the latter
689*83ee113eSDavid van Moolenbroek 	 * to detect the presence of the former.
690*83ee113eSDavid van Moolenbroek 	 */
691*83ee113eSDavid van Moolenbroek 	} else if ((oc = lookup_option(&fqdn_universe, packet->options,
692*83ee113eSDavid van Moolenbroek 				       FQDN_ENCODED)) &&
693*83ee113eSDavid van Moolenbroek 		   buffer_allocate(&bp, ddns_fwd_name.len + 5, MDL)) {
694*83ee113eSDavid van Moolenbroek 		bp -> data [0] = server_updates_a;
695*83ee113eSDavid van Moolenbroek 		if (!save_option_buffer(&fqdn_universe, options,
696*83ee113eSDavid van Moolenbroek 					bp, &bp->data [0], 1,
697*83ee113eSDavid van Moolenbroek 					FQDN_SERVER_UPDATE, 0))
698*83ee113eSDavid van Moolenbroek 			goto badfqdn;
699*83ee113eSDavid van Moolenbroek 		bp -> data [1] = server_updates_a;
700*83ee113eSDavid van Moolenbroek 		if (!save_option_buffer(&fqdn_universe, options,
701*83ee113eSDavid van Moolenbroek 					 bp, &bp->data [1], 1,
702*83ee113eSDavid van Moolenbroek 					 FQDN_NO_CLIENT_UPDATE, 0))
703*83ee113eSDavid van Moolenbroek 			goto badfqdn;
704*83ee113eSDavid van Moolenbroek 
705*83ee113eSDavid van Moolenbroek 		/* Do the same encoding the client did. */
706*83ee113eSDavid van Moolenbroek 		if (evaluate_boolean_option_cache(&ignorep, packet, lease,
707*83ee113eSDavid van Moolenbroek 						  NULL, packet->options,
708*83ee113eSDavid van Moolenbroek 						  options, scope, oc, MDL))
709*83ee113eSDavid van Moolenbroek 			bp -> data [2] = 1;
710*83ee113eSDavid van Moolenbroek 		else
711*83ee113eSDavid van Moolenbroek 			bp -> data [2] = 0;
712*83ee113eSDavid van Moolenbroek 		if (!save_option_buffer(&fqdn_universe, options,
713*83ee113eSDavid van Moolenbroek 					bp, &bp->data [2], 1,
714*83ee113eSDavid van Moolenbroek 					FQDN_ENCODED, 0))
715*83ee113eSDavid van Moolenbroek 			goto badfqdn;
716*83ee113eSDavid van Moolenbroek 		bp -> data [3] = 255;//isc_rcode_to_ns (rcode1);
717*83ee113eSDavid van Moolenbroek 		if (!save_option_buffer(&fqdn_universe, options,
718*83ee113eSDavid van Moolenbroek 					bp, &bp->data [3], 1,
719*83ee113eSDavid van Moolenbroek 					FQDN_RCODE1, 0))
720*83ee113eSDavid van Moolenbroek 			goto badfqdn;
721*83ee113eSDavid van Moolenbroek 		bp -> data [4] = 255;//isc_rcode_to_ns (rcode2);
722*83ee113eSDavid van Moolenbroek 		if (!save_option_buffer(&fqdn_universe, options,
723*83ee113eSDavid van Moolenbroek 					bp, &bp->data [4], 1,
724*83ee113eSDavid van Moolenbroek 					FQDN_RCODE2, 0))
725*83ee113eSDavid van Moolenbroek 			goto badfqdn;
726*83ee113eSDavid van Moolenbroek 		if (ddns_fwd_name.len) {
727*83ee113eSDavid van Moolenbroek 		    memcpy (&bp -> data [5],
728*83ee113eSDavid van Moolenbroek 			    ddns_fwd_name.data, ddns_fwd_name.len);
729*83ee113eSDavid van Moolenbroek 		    if (!save_option_buffer(&fqdn_universe, options,
730*83ee113eSDavid van Moolenbroek 					     bp, &bp->data [5],
731*83ee113eSDavid van Moolenbroek 					     ddns_fwd_name.len,
732*83ee113eSDavid van Moolenbroek 					     FQDN_FQDN, 0))
733*83ee113eSDavid van Moolenbroek 			goto badfqdn;
734*83ee113eSDavid van Moolenbroek 		}
735*83ee113eSDavid van Moolenbroek 	}
736*83ee113eSDavid van Moolenbroek 
737*83ee113eSDavid van Moolenbroek       badfqdn:
738*83ee113eSDavid van Moolenbroek       out:
739*83ee113eSDavid van Moolenbroek 	/*
740*83ee113eSDavid van Moolenbroek 	 * Final cleanup.
741*83ee113eSDavid van Moolenbroek 	 */
742*83ee113eSDavid van Moolenbroek 	if (ddns_cb != NULL) {
743*83ee113eSDavid van Moolenbroek 		ddns_cb_free(ddns_cb, MDL);
744*83ee113eSDavid van Moolenbroek 	}
745*83ee113eSDavid van Moolenbroek 
746*83ee113eSDavid van Moolenbroek 	data_string_forget(&d1, MDL);
747*83ee113eSDavid van Moolenbroek 	data_string_forget(&ddns_hostname, MDL);
748*83ee113eSDavid van Moolenbroek 	data_string_forget(&ddns_domainname, MDL);
749*83ee113eSDavid van Moolenbroek 	data_string_forget(&old_ddns_fwd_name, MDL);
750*83ee113eSDavid van Moolenbroek 	data_string_forget(&ddns_fwd_name, MDL);
751*83ee113eSDavid van Moolenbroek 	if (bp)
752*83ee113eSDavid van Moolenbroek 		buffer_dereference(&bp, MDL);
753*83ee113eSDavid van Moolenbroek 
754*83ee113eSDavid van Moolenbroek 	return result;
755*83ee113eSDavid van Moolenbroek }
756*83ee113eSDavid van Moolenbroek 
757*83ee113eSDavid van Moolenbroek /*%<
758*83ee113eSDavid van Moolenbroek  * Utility function to update text strings within a lease.
759*83ee113eSDavid van Moolenbroek  *
760*83ee113eSDavid van Moolenbroek  * The first issue is to find the proper scope.  Sometimes we shall be
761*83ee113eSDavid van Moolenbroek  * called with a pointer to the scope in other cases we need to find
762*83ee113eSDavid van Moolenbroek  * the proper lease and then get the scope.  Once we have the scope we update
763*83ee113eSDavid van Moolenbroek  * the proper strings, as indicated by the state value in the control block.
764*83ee113eSDavid van Moolenbroek  * Lastly, if we needed to find the scope we write it out, if we used a
765*83ee113eSDavid van Moolenbroek  * scope that was passed as an argument we don't write it, assuming that
766*83ee113eSDavid van Moolenbroek  * our caller (or his ...) will do the write.
767*83ee113eSDavid van Moolenbroek  *
768*83ee113eSDavid van Moolenbroek  *\li ddns_cb - the control block for the DDNS request
769*83ee113eSDavid van Moolenbroek  *
770*83ee113eSDavid van Moolenbroek  *\li inscope - a pointer to the scope to update.  This may be NULL
771*83ee113eSDavid van Moolenbroek  *    in which case we use the control block to find the lease and
772*83ee113eSDavid van Moolenbroek  *    then the scope.
773*83ee113eSDavid van Moolenbroek  *
774*83ee113eSDavid van Moolenbroek  * Returns
775*83ee113eSDavid van Moolenbroek  *\li ISC_R_SUCCESS
776*83ee113eSDavid van Moolenbroek  *
777*83ee113eSDavid van Moolenbroek  *\li ISC_R_FAILURE - The routine was unable to find an expected scope.
778*83ee113eSDavid van Moolenbroek  *    In some cases (static and inactive leases) we don't expect a scope
779*83ee113eSDavid van Moolenbroek  *    and return success.
780*83ee113eSDavid van Moolenbroek  */
781*83ee113eSDavid van Moolenbroek 
782*83ee113eSDavid van Moolenbroek static isc_result_t
ddns_update_lease_text(dhcp_ddns_cb_t * ddns_cb,struct binding_scope ** inscope)783*83ee113eSDavid van Moolenbroek ddns_update_lease_text(dhcp_ddns_cb_t        *ddns_cb,
784*83ee113eSDavid van Moolenbroek 		       struct binding_scope **inscope)
785*83ee113eSDavid van Moolenbroek {
786*83ee113eSDavid van Moolenbroek 	struct binding_scope **scope  = NULL;
787*83ee113eSDavid van Moolenbroek 	struct lease          *lease  = NULL;
788*83ee113eSDavid van Moolenbroek 	struct iasubopt       *lease6 = NULL;
789*83ee113eSDavid van Moolenbroek 	struct ipv6_pool      *pool   = NULL;
790*83ee113eSDavid van Moolenbroek 	struct in6_addr        addr;
791*83ee113eSDavid van Moolenbroek 	struct data_string     lease_dhcid;
792*83ee113eSDavid van Moolenbroek 
793*83ee113eSDavid van Moolenbroek 	/*
794*83ee113eSDavid van Moolenbroek 	 * If the lease was static (for a fixed address)
795*83ee113eSDavid van Moolenbroek 	 * we don't need to do any work.
796*83ee113eSDavid van Moolenbroek 	 */
797*83ee113eSDavid van Moolenbroek 	if (ddns_cb->flags & DDNS_STATIC_LEASE)
798*83ee113eSDavid van Moolenbroek 		return (ISC_R_SUCCESS);
799*83ee113eSDavid van Moolenbroek 
800*83ee113eSDavid van Moolenbroek 	/*
801*83ee113eSDavid van Moolenbroek 	 * If we are processing an expired or released v6 lease
802*83ee113eSDavid van Moolenbroek 	 * or some types of v4 leases we don't actually have a
803*83ee113eSDavid van Moolenbroek 	 * scope to update
804*83ee113eSDavid van Moolenbroek 	 */
805*83ee113eSDavid van Moolenbroek 	if ((ddns_cb->flags & DDNS_ACTIVE_LEASE) == 0)
806*83ee113eSDavid van Moolenbroek 		return (ISC_R_SUCCESS);
807*83ee113eSDavid van Moolenbroek 
808*83ee113eSDavid van Moolenbroek 	if (inscope != NULL) {
809*83ee113eSDavid van Moolenbroek 		scope = inscope;
810*83ee113eSDavid van Moolenbroek 	} else if (ddns_cb->address.len == 4) {
811*83ee113eSDavid van Moolenbroek 		if (find_lease_by_ip_addr(&lease, ddns_cb->address, MDL) != 0){
812*83ee113eSDavid van Moolenbroek 			scope = &(lease->scope);
813*83ee113eSDavid van Moolenbroek 		}
814*83ee113eSDavid van Moolenbroek 	} else if (ddns_cb->address.len == 16) {
815*83ee113eSDavid van Moolenbroek 		memcpy(&addr, &ddns_cb->address.iabuf, 16);
816*83ee113eSDavid van Moolenbroek 		if ((find_ipv6_pool(&pool, D6O_IA_TA, &addr) ==
817*83ee113eSDavid van Moolenbroek 		     ISC_R_SUCCESS) ||
818*83ee113eSDavid van Moolenbroek 		    (find_ipv6_pool(&pool, D6O_IA_NA, &addr) ==
819*83ee113eSDavid van Moolenbroek 		     ISC_R_SUCCESS)) {
820*83ee113eSDavid van Moolenbroek 			if (iasubopt_hash_lookup(&lease6,  pool->leases,
821*83ee113eSDavid van Moolenbroek 						 &addr, 16, MDL)) {
822*83ee113eSDavid van Moolenbroek 				scope = &(lease6->scope);
823*83ee113eSDavid van Moolenbroek 			}
824*83ee113eSDavid van Moolenbroek 			ipv6_pool_dereference(&pool, MDL);
825*83ee113eSDavid van Moolenbroek 		}
826*83ee113eSDavid van Moolenbroek 	} else {
827*83ee113eSDavid van Moolenbroek 		log_fatal("Impossible condition at %s:%d.", MDL);
828*83ee113eSDavid van Moolenbroek 	}
829*83ee113eSDavid van Moolenbroek 
830*83ee113eSDavid van Moolenbroek 	if (scope == NULL) {
831*83ee113eSDavid van Moolenbroek 		/* If necessary get rid of the lease */
832*83ee113eSDavid van Moolenbroek 		if (lease) {
833*83ee113eSDavid van Moolenbroek 			lease_dereference(&lease, MDL);
834*83ee113eSDavid van Moolenbroek 		}
835*83ee113eSDavid van Moolenbroek 		else if (lease6) {
836*83ee113eSDavid van Moolenbroek 			iasubopt_dereference(&lease6, MDL);
837*83ee113eSDavid van Moolenbroek 		}
838*83ee113eSDavid van Moolenbroek 
839*83ee113eSDavid van Moolenbroek 		return(ISC_R_FAILURE);
840*83ee113eSDavid van Moolenbroek 	}
841*83ee113eSDavid van Moolenbroek 
842*83ee113eSDavid van Moolenbroek 	/* We now have a scope and can proceed to update it */
843*83ee113eSDavid van Moolenbroek 	switch(ddns_cb->state) {
844*83ee113eSDavid van Moolenbroek 	case DDNS_STATE_REM_PTR:
845*83ee113eSDavid van Moolenbroek 		unset(*scope, "ddns-rev-name");
846*83ee113eSDavid van Moolenbroek 		if ((ddns_cb->flags & DDNS_CLIENT_DID_UPDATE) != 0) {
847*83ee113eSDavid van Moolenbroek 			unset(*scope, "ddns-client-fqdn");
848*83ee113eSDavid van Moolenbroek 		}
849*83ee113eSDavid van Moolenbroek 		break;
850*83ee113eSDavid van Moolenbroek 
851*83ee113eSDavid van Moolenbroek 	case DDNS_STATE_ADD_PTR:
852*83ee113eSDavid van Moolenbroek 	case DDNS_STATE_CLEANUP:
853*83ee113eSDavid van Moolenbroek 		bind_ds_value(scope, "ddns-rev-name", &ddns_cb->rev_name);
854*83ee113eSDavid van Moolenbroek 		if ((ddns_cb->flags & DDNS_UPDATE_ADDR) == 0) {
855*83ee113eSDavid van Moolenbroek 			bind_ds_value(scope, "ddns-client-fqdn",
856*83ee113eSDavid van Moolenbroek 				      &ddns_cb->fwd_name);
857*83ee113eSDavid van Moolenbroek 		}
858*83ee113eSDavid van Moolenbroek 		break;
859*83ee113eSDavid van Moolenbroek 
860*83ee113eSDavid van Moolenbroek 	case DDNS_STATE_ADD_FW_YXDHCID:
861*83ee113eSDavid van Moolenbroek 	case DDNS_STATE_ADD_FW_NXDOMAIN:
862*83ee113eSDavid van Moolenbroek 		bind_ds_value(scope, "ddns-fwd-name", &ddns_cb->fwd_name);
863*83ee113eSDavid van Moolenbroek 
864*83ee113eSDavid van Moolenbroek 		if (ddns_cb->lease_tag == ddns_standard_tag) {
865*83ee113eSDavid van Moolenbroek 			bind_ds_value(scope, ddns_standard_tag, &ddns_cb->dhcid);
866*83ee113eSDavid van Moolenbroek 		} else {
867*83ee113eSDavid van Moolenbroek 			/* convert from dns version to lease version of dhcid */
868*83ee113eSDavid van Moolenbroek 			memset(&lease_dhcid, 0, sizeof(lease_dhcid));
869*83ee113eSDavid van Moolenbroek 			dhcid_tolease(&ddns_cb->dhcid, &lease_dhcid);
870*83ee113eSDavid van Moolenbroek 			bind_ds_value(scope, ddns_interim_tag, &lease_dhcid);
871*83ee113eSDavid van Moolenbroek 			data_string_forget(&lease_dhcid, MDL);
872*83ee113eSDavid van Moolenbroek 		}
873*83ee113eSDavid van Moolenbroek 		break;
874*83ee113eSDavid van Moolenbroek 
875*83ee113eSDavid van Moolenbroek 	case DDNS_STATE_REM_FW_NXRR:
876*83ee113eSDavid van Moolenbroek 	case DDNS_STATE_REM_FW_YXDHCID:
877*83ee113eSDavid van Moolenbroek 		unset(*scope, "ddns-fwd-name");
878*83ee113eSDavid van Moolenbroek 		unset(*scope, ddns_cb->lease_tag);
879*83ee113eSDavid van Moolenbroek 		break;
880*83ee113eSDavid van Moolenbroek 	}
881*83ee113eSDavid van Moolenbroek 
882*83ee113eSDavid van Moolenbroek 	/* If necessary write it out and get rid of the lease */
883*83ee113eSDavid van Moolenbroek 	if (lease) {
884*83ee113eSDavid van Moolenbroek 		write_lease(lease);
885*83ee113eSDavid van Moolenbroek 		lease_dereference(&lease, MDL);
886*83ee113eSDavid van Moolenbroek 	} else if (lease6) {
887*83ee113eSDavid van Moolenbroek 		write_ia(lease6->ia);
888*83ee113eSDavid van Moolenbroek 		iasubopt_dereference(&lease6, MDL);
889*83ee113eSDavid van Moolenbroek 	}
890*83ee113eSDavid van Moolenbroek 
891*83ee113eSDavid van Moolenbroek 	return(ISC_R_SUCCESS);
892*83ee113eSDavid van Moolenbroek }
893*83ee113eSDavid van Moolenbroek 
894*83ee113eSDavid van Moolenbroek #ifdef notdef
895*83ee113eSDavid van Moolenbroek /*
896*83ee113eSDavid van Moolenbroek  * This function should be called when update_lease_ptr function fails.
897*83ee113eSDavid van Moolenbroek  * It does inform user about the condition, provides some hints how to
898*83ee113eSDavid van Moolenbroek  * resolve this and dies gracefully. This can happend in at least three
899*83ee113eSDavid van Moolenbroek  * cases (all are configuration mistakes):
900*83ee113eSDavid van Moolenbroek  * a) IPv4: user have duplicate fixed-address entries (the same
901*83ee113eSDavid van Moolenbroek  *    address is defined twice). We may have found wrong lease.
902*83ee113eSDavid van Moolenbroek  * b) IPv6: user have overlapping pools (we tried to find
903*83ee113eSDavid van Moolenbroek  *    a lease in a wrong pool)
904*83ee113eSDavid van Moolenbroek  * c) IPv6: user have duplicate fixed-address6 entires (the same
905*83ee113eSDavid van Moolenbroek  *    address is defined twice). We may have found wrong lease.
906*83ee113eSDavid van Moolenbroek  *
907*83ee113eSDavid van Moolenbroek  * Comment: while it would be possible to recover from both cases
908*83ee113eSDavid van Moolenbroek  * by forcibly searching for leases in *all* following pools, that would
909*83ee113eSDavid van Moolenbroek  * only hide the real problem - a misconfiguration. Proper solution
910*83ee113eSDavid van Moolenbroek  * is to log the problem, die and let the user fix his config file.
911*83ee113eSDavid van Moolenbroek  */
912*83ee113eSDavid van Moolenbroek void
update_lease_failed(struct lease * lease,struct iasubopt * lease6,dhcp_ddns_cb_t * ddns_cb,dhcp_ddns_cb_t * ddns_cb_set,const char * file,int line)913*83ee113eSDavid van Moolenbroek update_lease_failed(struct lease *lease,
914*83ee113eSDavid van Moolenbroek 		    struct iasubopt *lease6,
915*83ee113eSDavid van Moolenbroek 		    dhcp_ddns_cb_t  *ddns_cb,
916*83ee113eSDavid van Moolenbroek 		    dhcp_ddns_cb_t  *ddns_cb_set,
917*83ee113eSDavid van Moolenbroek 		    const char * file, int line)
918*83ee113eSDavid van Moolenbroek {
919*83ee113eSDavid van Moolenbroek 	char lease_address[MAX_ADDRESS_STRING_LEN + 64];
920*83ee113eSDavid van Moolenbroek 	char reason[128]; /* likely reason */
921*83ee113eSDavid van Moolenbroek 
922*83ee113eSDavid van Moolenbroek 	sprintf(reason, "unknown");
923*83ee113eSDavid van Moolenbroek 	sprintf(lease_address, "unknown");
924*83ee113eSDavid van Moolenbroek 
925*83ee113eSDavid van Moolenbroek 	/*
926*83ee113eSDavid van Moolenbroek 	 * let's pretend that everything is ok, so we can continue for
927*83ee113eSDavid van Moolenbroek 	 * information gathering purposes
928*83ee113eSDavid van Moolenbroek 	 */
929*83ee113eSDavid van Moolenbroek 
930*83ee113eSDavid van Moolenbroek 	if (ddns_cb != NULL) {
931*83ee113eSDavid van Moolenbroek 		strncpy(lease_address, piaddr(ddns_cb->address),
932*83ee113eSDavid van Moolenbroek 			MAX_ADDRESS_STRING_LEN);
933*83ee113eSDavid van Moolenbroek 
934*83ee113eSDavid van Moolenbroek 		if (ddns_cb->address.len == 4) {
935*83ee113eSDavid van Moolenbroek 			sprintf(reason, "duplicate IPv4 fixed-address entry");
936*83ee113eSDavid van Moolenbroek 		} else if (ddns_cb->address.len == 16) {
937*83ee113eSDavid van Moolenbroek 			sprintf(reason, "duplicate IPv6 fixed-address6 entry "
938*83ee113eSDavid van Moolenbroek 				"or overlapping pools");
939*83ee113eSDavid van Moolenbroek 		} else {
940*83ee113eSDavid van Moolenbroek 			/*
941*83ee113eSDavid van Moolenbroek 			 * Should not happen. We have non-IPv4, non-IPv6
942*83ee113eSDavid van Moolenbroek 			 * address. Something is very wrong here.
943*83ee113eSDavid van Moolenbroek 			 */
944*83ee113eSDavid van Moolenbroek 			sprintf(reason, "corrupted ddns_cb structure (address "
945*83ee113eSDavid van Moolenbroek 				"length is %d)", ddns_cb->address.len);
946*83ee113eSDavid van Moolenbroek 		}
947*83ee113eSDavid van Moolenbroek 	}
948*83ee113eSDavid van Moolenbroek 
949*83ee113eSDavid van Moolenbroek 	log_error("Failed to properly update internal lease structure with "
950*83ee113eSDavid van Moolenbroek 		  "DDNS");
951*83ee113eSDavid van Moolenbroek 	log_error("control block structures. Tried to update lease for"
952*83ee113eSDavid van Moolenbroek 		  "%s address, ddns_cb=%p.", lease_address, ddns_cb);
953*83ee113eSDavid van Moolenbroek 
954*83ee113eSDavid van Moolenbroek 	log_error("%s", "");
955*83ee113eSDavid van Moolenbroek 	log_error("This condition can occur, if DHCP server configuration is "
956*83ee113eSDavid van Moolenbroek 		  "inconsistent.");
957*83ee113eSDavid van Moolenbroek 	log_error("In particular, please do check that your configuration:");
958*83ee113eSDavid van Moolenbroek 	log_error("a) does not have overlapping pools (especially containing");
959*83ee113eSDavid van Moolenbroek 	log_error("   %s address).", lease_address);
960*83ee113eSDavid van Moolenbroek 	log_error("b) there are no duplicate fixed-address or fixed-address6");
961*83ee113eSDavid van Moolenbroek 	log_error("entries for the %s address.", lease_address);
962*83ee113eSDavid van Moolenbroek 	log_error("%s", "");
963*83ee113eSDavid van Moolenbroek 	log_error("Possible reason for this failure: %s", reason);
964*83ee113eSDavid van Moolenbroek 
965*83ee113eSDavid van Moolenbroek 	log_fatal("%s(%d): Failed to update lease database with DDNS info for "
966*83ee113eSDavid van Moolenbroek 		  "address %s. Lease database inconsistent. Unable to recover."
967*83ee113eSDavid van Moolenbroek 		  " Terminating.", file, line, lease_address);
968*83ee113eSDavid van Moolenbroek }
969*83ee113eSDavid van Moolenbroek #endif
970*83ee113eSDavid van Moolenbroek 
971*83ee113eSDavid van Moolenbroek /*
972*83ee113eSDavid van Moolenbroek  * utility function to update found lease. It does extra checks
973*83ee113eSDavid van Moolenbroek  * that we are indeed updating the right lease. It may happen
974*83ee113eSDavid van Moolenbroek  * that user have duplicate fixed-address entries, so we attempt
975*83ee113eSDavid van Moolenbroek  * to update wrong lease. See also safe_lease6_update.
976*83ee113eSDavid van Moolenbroek  */
977*83ee113eSDavid van Moolenbroek 
978*83ee113eSDavid van Moolenbroek static void
safe_lease_update(struct lease * lease,dhcp_ddns_cb_t * oldcb,dhcp_ddns_cb_t * newcb,const char * file,int line)979*83ee113eSDavid van Moolenbroek safe_lease_update(struct lease *lease,
980*83ee113eSDavid van Moolenbroek 		  dhcp_ddns_cb_t *oldcb,
981*83ee113eSDavid van Moolenbroek 		  dhcp_ddns_cb_t *newcb,
982*83ee113eSDavid van Moolenbroek 		  const char *file, int line)
983*83ee113eSDavid van Moolenbroek {
984*83ee113eSDavid van Moolenbroek 	if (lease == NULL) {
985*83ee113eSDavid van Moolenbroek 		/* should never get here */
986*83ee113eSDavid van Moolenbroek 		log_fatal("Impossible condition at %s:%d (called from %s:%d).",
987*83ee113eSDavid van Moolenbroek 			  MDL, file, line);
988*83ee113eSDavid van Moolenbroek 	}
989*83ee113eSDavid van Moolenbroek 
990*83ee113eSDavid van Moolenbroek 	if ( (lease->ddns_cb == NULL) && (newcb == NULL) ) {
991*83ee113eSDavid van Moolenbroek 		/*
992*83ee113eSDavid van Moolenbroek 		 * Trying to clean up pointer that is already null. We
993*83ee113eSDavid van Moolenbroek 		 * are most likely trying to update wrong lease here.
994*83ee113eSDavid van Moolenbroek 		 */
995*83ee113eSDavid van Moolenbroek 
996*83ee113eSDavid van Moolenbroek 		/*
997*83ee113eSDavid van Moolenbroek 		 * Previously this error message popped out during
998*83ee113eSDavid van Moolenbroek 		 * DNS update for fixed leases.  As we no longer
999*83ee113eSDavid van Moolenbroek 		 * try to update the lease for a fixed (static) lease
1000*83ee113eSDavid van Moolenbroek 		 * this should not be a problem.
1001*83ee113eSDavid van Moolenbroek 		 */
1002*83ee113eSDavid van Moolenbroek 		log_error("%s(%d): Invalid lease update. Tried to "
1003*83ee113eSDavid van Moolenbroek 			  "clear already NULL DDNS control block "
1004*83ee113eSDavid van Moolenbroek 			  "pointer for lease %s.",
1005*83ee113eSDavid van Moolenbroek 			  file, line, piaddr(lease->ip_addr) );
1006*83ee113eSDavid van Moolenbroek 
1007*83ee113eSDavid van Moolenbroek #if defined (DNS_UPDATES_MEMORY_CHECKS)
1008*83ee113eSDavid van Moolenbroek 		update_lease_failed(lease, NULL, oldcb, newcb, file, line);
1009*83ee113eSDavid van Moolenbroek #endif
1010*83ee113eSDavid van Moolenbroek 		/*
1011*83ee113eSDavid van Moolenbroek 		 * May not reach this: update_lease_failed calls
1012*83ee113eSDavid van Moolenbroek 		 * log_fatal.
1013*83ee113eSDavid van Moolenbroek 		 */
1014*83ee113eSDavid van Moolenbroek 		return;
1015*83ee113eSDavid van Moolenbroek 	}
1016*83ee113eSDavid van Moolenbroek 
1017*83ee113eSDavid van Moolenbroek 	if ( (lease->ddns_cb != NULL) && (lease->ddns_cb != oldcb) ) {
1018*83ee113eSDavid van Moolenbroek 		/*
1019*83ee113eSDavid van Moolenbroek 		 * There is existing cb structure, but it differs from
1020*83ee113eSDavid van Moolenbroek 		 * what we expected to see there. Most likely we are
1021*83ee113eSDavid van Moolenbroek 		 * trying to update wrong lease.
1022*83ee113eSDavid van Moolenbroek 		 */
1023*83ee113eSDavid van Moolenbroek 		log_error("%s(%d): Failed to update internal lease "
1024*83ee113eSDavid van Moolenbroek 			  "structure with DDNS control block. Existing"
1025*83ee113eSDavid van Moolenbroek 			  " ddns_cb structure does not match "
1026*83ee113eSDavid van Moolenbroek 			  "expectations.IPv4=%s, old ddns_cb=%p, tried"
1027*83ee113eSDavid van Moolenbroek 			  "to update to new ddns_cb=%p", file, line,
1028*83ee113eSDavid van Moolenbroek 			  piaddr(lease->ip_addr), oldcb,  newcb);
1029*83ee113eSDavid van Moolenbroek 
1030*83ee113eSDavid van Moolenbroek #if defined (DNS_UPDATES_MEMORY_CHECKS)
1031*83ee113eSDavid van Moolenbroek 		update_lease_failed(lease, NULL, oldcb, newcb, file, line);
1032*83ee113eSDavid van Moolenbroek #endif
1033*83ee113eSDavid van Moolenbroek 		/*
1034*83ee113eSDavid van Moolenbroek 		 * May not reach this: update_lease_failed calls
1035*83ee113eSDavid van Moolenbroek 		 * log_fatal.
1036*83ee113eSDavid van Moolenbroek 		 */
1037*83ee113eSDavid van Moolenbroek 		return;
1038*83ee113eSDavid van Moolenbroek 	}
1039*83ee113eSDavid van Moolenbroek 
1040*83ee113eSDavid van Moolenbroek 	/* additional IPv4 specific checks may be added here */
1041*83ee113eSDavid van Moolenbroek 
1042*83ee113eSDavid van Moolenbroek 	/* update the lease */
1043*83ee113eSDavid van Moolenbroek 	lease->ddns_cb = newcb;
1044*83ee113eSDavid van Moolenbroek }
1045*83ee113eSDavid van Moolenbroek 
1046*83ee113eSDavid van Moolenbroek static void
safe_lease6_update(struct iasubopt * lease6,dhcp_ddns_cb_t * oldcb,dhcp_ddns_cb_t * newcb,const char * file,int line)1047*83ee113eSDavid van Moolenbroek safe_lease6_update(struct iasubopt *lease6,
1048*83ee113eSDavid van Moolenbroek 		   dhcp_ddns_cb_t *oldcb,
1049*83ee113eSDavid van Moolenbroek 		   dhcp_ddns_cb_t *newcb,
1050*83ee113eSDavid van Moolenbroek 		   const char *file, int line)
1051*83ee113eSDavid van Moolenbroek {
1052*83ee113eSDavid van Moolenbroek 	char addrbuf[MAX_ADDRESS_STRING_LEN];
1053*83ee113eSDavid van Moolenbroek 
1054*83ee113eSDavid van Moolenbroek 	if (lease6 == NULL) {
1055*83ee113eSDavid van Moolenbroek 		/* should never get here */
1056*83ee113eSDavid van Moolenbroek 		log_fatal("Impossible condition at %s:%d (called from %s:%d).",
1057*83ee113eSDavid van Moolenbroek 			  MDL, file, line);
1058*83ee113eSDavid van Moolenbroek 	}
1059*83ee113eSDavid van Moolenbroek 
1060*83ee113eSDavid van Moolenbroek 	if ( (lease6->ddns_cb == NULL) && (newcb == NULL) ) {
1061*83ee113eSDavid van Moolenbroek 		inet_ntop(AF_INET6, &lease6->addr, addrbuf,
1062*83ee113eSDavid van Moolenbroek 			  MAX_ADDRESS_STRING_LEN);
1063*83ee113eSDavid van Moolenbroek 		/*
1064*83ee113eSDavid van Moolenbroek 		 * Trying to clean up pointer that is already null. We
1065*83ee113eSDavid van Moolenbroek 		 * are most likely trying to update wrong lease here.
1066*83ee113eSDavid van Moolenbroek 		 */
1067*83ee113eSDavid van Moolenbroek 		log_error("%s(%d): Failed to update internal lease "
1068*83ee113eSDavid van Moolenbroek 			  "structure. Tried to clear already NULL "
1069*83ee113eSDavid van Moolenbroek 			  "DDNS control block pointer for lease %s.",
1070*83ee113eSDavid van Moolenbroek 			  file, line, addrbuf);
1071*83ee113eSDavid van Moolenbroek 
1072*83ee113eSDavid van Moolenbroek #if defined (DNS_UPDATES_MEMORY_CHECKS)
1073*83ee113eSDavid van Moolenbroek 		update_lease_failed(NULL, lease6, oldcb, newcb, file, line);
1074*83ee113eSDavid van Moolenbroek #endif
1075*83ee113eSDavid van Moolenbroek 
1076*83ee113eSDavid van Moolenbroek 		/*
1077*83ee113eSDavid van Moolenbroek 		 * May not reach this: update_lease_failed calls
1078*83ee113eSDavid van Moolenbroek 		 * log_fatal.
1079*83ee113eSDavid van Moolenbroek 		 */
1080*83ee113eSDavid van Moolenbroek 		return;
1081*83ee113eSDavid van Moolenbroek 	}
1082*83ee113eSDavid van Moolenbroek 
1083*83ee113eSDavid van Moolenbroek 	if ( (lease6->ddns_cb != NULL) && (lease6->ddns_cb != oldcb) ) {
1084*83ee113eSDavid van Moolenbroek 		/*
1085*83ee113eSDavid van Moolenbroek 		 * there is existing cb structure, but it differs from
1086*83ee113eSDavid van Moolenbroek 		 * what we expected to see there. Most likely we are
1087*83ee113eSDavid van Moolenbroek 		 * trying to update wrong lease.
1088*83ee113eSDavid van Moolenbroek 		 */
1089*83ee113eSDavid van Moolenbroek 		inet_ntop(AF_INET6, &lease6->addr, addrbuf,
1090*83ee113eSDavid van Moolenbroek 			  MAX_ADDRESS_STRING_LEN);
1091*83ee113eSDavid van Moolenbroek 
1092*83ee113eSDavid van Moolenbroek 		log_error("%s(%d): Failed to update internal lease "
1093*83ee113eSDavid van Moolenbroek 			  "structure with DDNS control block. Existing"
1094*83ee113eSDavid van Moolenbroek 			  " ddns_cb structure does not match "
1095*83ee113eSDavid van Moolenbroek 			  "expectations.IPv6=%s, old ddns_cb=%p, tried"
1096*83ee113eSDavid van Moolenbroek 			  "to update to new ddns_cb=%p", file, line,
1097*83ee113eSDavid van Moolenbroek 			  addrbuf, oldcb,  newcb);
1098*83ee113eSDavid van Moolenbroek 
1099*83ee113eSDavid van Moolenbroek #if defined (DNS_UPDATES_MEMORY_CHECKS)
1100*83ee113eSDavid van Moolenbroek 		update_lease_failed(NULL, lease6, oldcb, newcb, file, line);
1101*83ee113eSDavid van Moolenbroek #endif
1102*83ee113eSDavid van Moolenbroek 		/*
1103*83ee113eSDavid van Moolenbroek 		 * May not reach this: update_lease_failed calls
1104*83ee113eSDavid van Moolenbroek 		 * log_fatal.
1105*83ee113eSDavid van Moolenbroek 		 */
1106*83ee113eSDavid van Moolenbroek 		return;
1107*83ee113eSDavid van Moolenbroek 	}
1108*83ee113eSDavid van Moolenbroek 	/* additional IPv6 specific checks may be added here */
1109*83ee113eSDavid van Moolenbroek 
1110*83ee113eSDavid van Moolenbroek 	/* update the lease */
1111*83ee113eSDavid van Moolenbroek 	lease6->ddns_cb = newcb;
1112*83ee113eSDavid van Moolenbroek }
1113*83ee113eSDavid van Moolenbroek 
1114*83ee113eSDavid van Moolenbroek /*
1115*83ee113eSDavid van Moolenbroek  * Utility function to update the pointer to the DDNS control block
1116*83ee113eSDavid van Moolenbroek  * in a lease.
1117*83ee113eSDavid van Moolenbroek  * SUCCESS - able to update the pointer
1118*83ee113eSDavid van Moolenbroek  * FAILURE - lease didn't exist or sanity checks failed
1119*83ee113eSDavid van Moolenbroek  * lease and lease6 may be empty in which case we attempt to find
1120*83ee113eSDavid van Moolenbroek  * the lease from the ddns_cb information.
1121*83ee113eSDavid van Moolenbroek  * ddns_cb is the control block to use if a lookup is necessary
1122*83ee113eSDavid van Moolenbroek  * ddns_cb_set is the pointer to insert into the lease and may be NULL
1123*83ee113eSDavid van Moolenbroek  * The last two arguments may look odd as they will be the same much of the
1124*83ee113eSDavid van Moolenbroek  * time, but I need an argument to tell me if I'm setting or clearing in
1125*83ee113eSDavid van Moolenbroek  * addition to the address information from the cb to look up the lease.
1126*83ee113eSDavid van Moolenbroek  * using the same value twice allows me more flexibility.
1127*83ee113eSDavid van Moolenbroek  */
1128*83ee113eSDavid van Moolenbroek 
1129*83ee113eSDavid van Moolenbroek static isc_result_t
ddns_update_lease_ptr(struct lease * lease,struct iasubopt * lease6,dhcp_ddns_cb_t * ddns_cb,dhcp_ddns_cb_t * ddns_cb_set,const char * file,int line)1130*83ee113eSDavid van Moolenbroek ddns_update_lease_ptr(struct lease    *lease,
1131*83ee113eSDavid van Moolenbroek 		      struct iasubopt *lease6,
1132*83ee113eSDavid van Moolenbroek 		      dhcp_ddns_cb_t  *ddns_cb,
1133*83ee113eSDavid van Moolenbroek 		      dhcp_ddns_cb_t  *ddns_cb_set,
1134*83ee113eSDavid van Moolenbroek 		      const char * file, int line)
1135*83ee113eSDavid van Moolenbroek {
1136*83ee113eSDavid van Moolenbroek 	char ddns_address[MAX_ADDRESS_STRING_LEN];
1137*83ee113eSDavid van Moolenbroek 	sprintf(ddns_address, "unknown");
1138*83ee113eSDavid van Moolenbroek 	if (ddns_cb == NULL) {
1139*83ee113eSDavid van Moolenbroek 		log_info("%s(%d): No control block for lease update",
1140*83ee113eSDavid van Moolenbroek 			 file, line);
1141*83ee113eSDavid van Moolenbroek 		return (ISC_R_FAILURE);
1142*83ee113eSDavid van Moolenbroek 	}
1143*83ee113eSDavid van Moolenbroek 	else {
1144*83ee113eSDavid van Moolenbroek 		strncpy(ddns_address, piaddr(ddns_cb->address),
1145*83ee113eSDavid van Moolenbroek 			MAX_ADDRESS_STRING_LEN);
1146*83ee113eSDavid van Moolenbroek 	}
1147*83ee113eSDavid van Moolenbroek #if defined (DEBUG_DNS_UPDATES)
1148*83ee113eSDavid van Moolenbroek 	log_info("%s(%d): Updating lease_ptr for ddns_cp=%p (addr=%s)",
1149*83ee113eSDavid van Moolenbroek 		 file, line, ddns_cb, ddns_address );
1150*83ee113eSDavid van Moolenbroek #endif
1151*83ee113eSDavid van Moolenbroek 
1152*83ee113eSDavid van Moolenbroek 	/*
1153*83ee113eSDavid van Moolenbroek 	 * If the lease was static (for a fixed address)
1154*83ee113eSDavid van Moolenbroek 	 * we don't need to do any work.
1155*83ee113eSDavid van Moolenbroek 	 */
1156*83ee113eSDavid van Moolenbroek 	if (ddns_cb->flags & DDNS_STATIC_LEASE) {
1157*83ee113eSDavid van Moolenbroek #if defined (DEBUG_DNS_UPDATES)
1158*83ee113eSDavid van Moolenbroek 		log_info("lease is static, returning");
1159*83ee113eSDavid van Moolenbroek #endif
1160*83ee113eSDavid van Moolenbroek 		return (ISC_R_SUCCESS);
1161*83ee113eSDavid van Moolenbroek 	}
1162*83ee113eSDavid van Moolenbroek 
1163*83ee113eSDavid van Moolenbroek 	/*
1164*83ee113eSDavid van Moolenbroek 	 * If we are processing an expired or released v6 lease
1165*83ee113eSDavid van Moolenbroek 	 * we don't actually have a lease to update
1166*83ee113eSDavid van Moolenbroek 	 */
1167*83ee113eSDavid van Moolenbroek 	if ((ddns_cb->address.len == 16) &&
1168*83ee113eSDavid van Moolenbroek 	    ((ddns_cb->flags & DDNS_ACTIVE_LEASE) == 0)) {
1169*83ee113eSDavid van Moolenbroek 		return (ISC_R_SUCCESS);
1170*83ee113eSDavid van Moolenbroek 	}
1171*83ee113eSDavid van Moolenbroek 
1172*83ee113eSDavid van Moolenbroek 	if (lease != NULL) {
1173*83ee113eSDavid van Moolenbroek 		safe_lease_update(lease, ddns_cb, ddns_cb_set,
1174*83ee113eSDavid van Moolenbroek 				  file, line);
1175*83ee113eSDavid van Moolenbroek 	} else if (lease6 != NULL) {
1176*83ee113eSDavid van Moolenbroek 		safe_lease6_update(lease6, ddns_cb, ddns_cb_set,
1177*83ee113eSDavid van Moolenbroek 				  file, line);
1178*83ee113eSDavid van Moolenbroek 	} else if (ddns_cb->address.len == 4) {
1179*83ee113eSDavid van Moolenbroek 		struct lease *find_lease = NULL;
1180*83ee113eSDavid van Moolenbroek 		if (find_lease_by_ip_addr(&find_lease,
1181*83ee113eSDavid van Moolenbroek 					  ddns_cb->address, MDL) != 0) {
1182*83ee113eSDavid van Moolenbroek #if defined (DEBUG_DNS_UPDATES)
1183*83ee113eSDavid van Moolenbroek 			log_info("%s(%d): find_lease_by_ip_addr(%s) successful:"
1184*83ee113eSDavid van Moolenbroek 				 "lease=%p", file, line, ddns_address,
1185*83ee113eSDavid van Moolenbroek 				 find_lease);
1186*83ee113eSDavid van Moolenbroek #endif
1187*83ee113eSDavid van Moolenbroek 
1188*83ee113eSDavid van Moolenbroek 			safe_lease_update(find_lease, ddns_cb,
1189*83ee113eSDavid van Moolenbroek 					  ddns_cb_set, file, line);
1190*83ee113eSDavid van Moolenbroek 			lease_dereference(&find_lease, MDL);
1191*83ee113eSDavid van Moolenbroek 		}
1192*83ee113eSDavid van Moolenbroek 		else {
1193*83ee113eSDavid van Moolenbroek 			log_error("%s(%d): ddns_update_lease_ptr failed. "
1194*83ee113eSDavid van Moolenbroek 				  "Lease for %s not found.",
1195*83ee113eSDavid van Moolenbroek 				  file, line, piaddr(ddns_cb->address));
1196*83ee113eSDavid van Moolenbroek 
1197*83ee113eSDavid van Moolenbroek #if defined (DNS_UPDATES_MEMORY_CHECKS)
1198*83ee113eSDavid van Moolenbroek 			update_lease_failed(NULL, NULL, ddns_cb, ddns_cb_set,
1199*83ee113eSDavid van Moolenbroek 					    file, line);
1200*83ee113eSDavid van Moolenbroek #endif
1201*83ee113eSDavid van Moolenbroek 			/*
1202*83ee113eSDavid van Moolenbroek 			 * may not reach this. update_lease_failed
1203*83ee113eSDavid van Moolenbroek 			 * calls log_fatal.
1204*83ee113eSDavid van Moolenbroek 			 */
1205*83ee113eSDavid van Moolenbroek 			return(ISC_R_FAILURE);
1206*83ee113eSDavid van Moolenbroek 
1207*83ee113eSDavid van Moolenbroek 		}
1208*83ee113eSDavid van Moolenbroek 	} else if (ddns_cb->address.len == 16) {
1209*83ee113eSDavid van Moolenbroek 		struct iasubopt *find_lease6 = NULL;
1210*83ee113eSDavid van Moolenbroek 		struct ipv6_pool *pool = NULL;
1211*83ee113eSDavid van Moolenbroek 		struct in6_addr addr;
1212*83ee113eSDavid van Moolenbroek 		char addrbuf[MAX_ADDRESS_STRING_LEN];
1213*83ee113eSDavid van Moolenbroek 
1214*83ee113eSDavid van Moolenbroek 		memcpy(&addr, &ddns_cb->address.iabuf, 16);
1215*83ee113eSDavid van Moolenbroek 		if ((find_ipv6_pool(&pool, D6O_IA_TA, &addr) !=
1216*83ee113eSDavid van Moolenbroek 		     ISC_R_SUCCESS) &&
1217*83ee113eSDavid van Moolenbroek 		    (find_ipv6_pool(&pool, D6O_IA_NA, &addr) !=
1218*83ee113eSDavid van Moolenbroek 		     ISC_R_SUCCESS)) {
1219*83ee113eSDavid van Moolenbroek 			inet_ntop(AF_INET6, &addr, addrbuf,
1220*83ee113eSDavid van Moolenbroek 				  MAX_ADDRESS_STRING_LEN);
1221*83ee113eSDavid van Moolenbroek 			log_error("%s(%d): Pool for lease %s not found.",
1222*83ee113eSDavid van Moolenbroek 				  file, line, addrbuf);
1223*83ee113eSDavid van Moolenbroek #if defined (DNS_UPDATES_MEMORY_CHECKS)
1224*83ee113eSDavid van Moolenbroek 			update_lease_failed(NULL, NULL, ddns_cb, ddns_cb_set,
1225*83ee113eSDavid van Moolenbroek 					    file, line);
1226*83ee113eSDavid van Moolenbroek #endif
1227*83ee113eSDavid van Moolenbroek 			/*
1228*83ee113eSDavid van Moolenbroek 			 * never reached. update_lease_failed
1229*83ee113eSDavid van Moolenbroek 			 * calls log_fatal.
1230*83ee113eSDavid van Moolenbroek 			 */
1231*83ee113eSDavid van Moolenbroek 			return(ISC_R_FAILURE);
1232*83ee113eSDavid van Moolenbroek 		}
1233*83ee113eSDavid van Moolenbroek 
1234*83ee113eSDavid van Moolenbroek 		if (iasubopt_hash_lookup(&find_lease6, pool->leases,
1235*83ee113eSDavid van Moolenbroek 					 &addr, 16, MDL)) {
1236*83ee113eSDavid van Moolenbroek 			find_lease6->ddns_cb = ddns_cb_set;
1237*83ee113eSDavid van Moolenbroek 			iasubopt_dereference(&find_lease6, MDL);
1238*83ee113eSDavid van Moolenbroek 		} else {
1239*83ee113eSDavid van Moolenbroek 			inet_ntop(AF_INET6, &addr, addrbuf,
1240*83ee113eSDavid van Moolenbroek 				  MAX_ADDRESS_STRING_LEN);
1241*83ee113eSDavid van Moolenbroek 			log_error("%s(%d): Lease %s not found within pool.",
1242*83ee113eSDavid van Moolenbroek 				  file, line, addrbuf);
1243*83ee113eSDavid van Moolenbroek #if defined (DNS_UPDATES_MEMORY_CHECKS)
1244*83ee113eSDavid van Moolenbroek 			update_lease_failed(NULL, NULL, ddns_cb, ddns_cb_set,
1245*83ee113eSDavid van Moolenbroek 					    file, line);
1246*83ee113eSDavid van Moolenbroek #endif
1247*83ee113eSDavid van Moolenbroek 			/*
1248*83ee113eSDavid van Moolenbroek 			 * never reached. update_lease_failed
1249*83ee113eSDavid van Moolenbroek 			 * calls log_fatal.
1250*83ee113eSDavid van Moolenbroek 			 */
1251*83ee113eSDavid van Moolenbroek 			return(ISC_R_FAILURE);
1252*83ee113eSDavid van Moolenbroek 		}
1253*83ee113eSDavid van Moolenbroek 		ipv6_pool_dereference(&pool, MDL);
1254*83ee113eSDavid van Moolenbroek 	} else {
1255*83ee113eSDavid van Moolenbroek 		/* shouldn't get here */
1256*83ee113eSDavid van Moolenbroek 		log_fatal("Impossible condition at %s:%d, called from %s:%d.",
1257*83ee113eSDavid van Moolenbroek 			  MDL, file, line);
1258*83ee113eSDavid van Moolenbroek 	}
1259*83ee113eSDavid van Moolenbroek 
1260*83ee113eSDavid van Moolenbroek 	return(ISC_R_SUCCESS);
1261*83ee113eSDavid van Moolenbroek }
1262*83ee113eSDavid van Moolenbroek 
1263*83ee113eSDavid van Moolenbroek static void
ddns_ptr_add(dhcp_ddns_cb_t * ddns_cb,isc_result_t eresult)1264*83ee113eSDavid van Moolenbroek ddns_ptr_add(dhcp_ddns_cb_t *ddns_cb,
1265*83ee113eSDavid van Moolenbroek 	     isc_result_t    eresult)
1266*83ee113eSDavid van Moolenbroek {
1267*83ee113eSDavid van Moolenbroek 	if (eresult == ISC_R_SUCCESS) {
1268*83ee113eSDavid van Moolenbroek 		log_info("Added reverse map from %.*s to %.*s",
1269*83ee113eSDavid van Moolenbroek 			 (int)ddns_cb->rev_name.len,
1270*83ee113eSDavid van Moolenbroek 			 (const char *)ddns_cb->rev_name.data,
1271*83ee113eSDavid van Moolenbroek 			 (int)ddns_cb->fwd_name.len,
1272*83ee113eSDavid van Moolenbroek 			 (const char *)ddns_cb->fwd_name.data);
1273*83ee113eSDavid van Moolenbroek 
1274*83ee113eSDavid van Moolenbroek 		ddns_update_lease_text(ddns_cb, NULL);
1275*83ee113eSDavid van Moolenbroek 	} else {
1276*83ee113eSDavid van Moolenbroek 		log_error("Unable to add reverse map from %.*s to %.*s: %s",
1277*83ee113eSDavid van Moolenbroek 			  (int)ddns_cb->rev_name.len,
1278*83ee113eSDavid van Moolenbroek 			  (const char *)ddns_cb->rev_name.data,
1279*83ee113eSDavid van Moolenbroek 			  (int)ddns_cb->fwd_name.len,
1280*83ee113eSDavid van Moolenbroek 			  (const char *)ddns_cb->fwd_name.data,
1281*83ee113eSDavid van Moolenbroek 			  isc_result_totext (eresult));
1282*83ee113eSDavid van Moolenbroek 	}
1283*83ee113eSDavid van Moolenbroek 
1284*83ee113eSDavid van Moolenbroek 	ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1285*83ee113eSDavid van Moolenbroek 	ddns_cb_free(ddns_cb, MDL);
1286*83ee113eSDavid van Moolenbroek 	/*
1287*83ee113eSDavid van Moolenbroek 	 * A single DDNS operation may require several calls depending on
1288*83ee113eSDavid van Moolenbroek 	 * the current state as the prerequisites for the first message
1289*83ee113eSDavid van Moolenbroek 	 * may not succeed requiring a second operation and potentially
1290*83ee113eSDavid van Moolenbroek 	 * a ptr operation after that.  The commit_leases operation is
1291*83ee113eSDavid van Moolenbroek 	 * invoked at the end of this set of operations in order to require
1292*83ee113eSDavid van Moolenbroek 	 * a single write for all of the changes.  We call commit_leases
1293*83ee113eSDavid van Moolenbroek 	 * here rather than immediately after the call to update the lease
1294*83ee113eSDavid van Moolenbroek 	 * text in order to save any previously written data.
1295*83ee113eSDavid van Moolenbroek 	 */
1296*83ee113eSDavid van Moolenbroek 	commit_leases();
1297*83ee113eSDavid van Moolenbroek 	return;
1298*83ee113eSDavid van Moolenbroek }
1299*83ee113eSDavid van Moolenbroek 
1300*83ee113eSDavid van Moolenbroek /*
1301*83ee113eSDavid van Moolenbroek  * action routine when trying to remove a pointer
1302*83ee113eSDavid van Moolenbroek  * this will be called after the ddns queries have completed
1303*83ee113eSDavid van Moolenbroek  * if we succeeded in removing the pointer we go to the next step (if any)
1304*83ee113eSDavid van Moolenbroek  * if not we cleanup and leave.
1305*83ee113eSDavid van Moolenbroek  */
1306*83ee113eSDavid van Moolenbroek 
1307*83ee113eSDavid van Moolenbroek static void
ddns_ptr_remove(dhcp_ddns_cb_t * ddns_cb,isc_result_t eresult)1308*83ee113eSDavid van Moolenbroek ddns_ptr_remove(dhcp_ddns_cb_t *ddns_cb,
1309*83ee113eSDavid van Moolenbroek 		isc_result_t    eresult)
1310*83ee113eSDavid van Moolenbroek {
1311*83ee113eSDavid van Moolenbroek 	isc_result_t result = eresult;
1312*83ee113eSDavid van Moolenbroek 
1313*83ee113eSDavid van Moolenbroek 	switch(eresult) {
1314*83ee113eSDavid van Moolenbroek 	case ISC_R_SUCCESS:
1315*83ee113eSDavid van Moolenbroek 		log_info("Removed reverse map on %.*s",
1316*83ee113eSDavid van Moolenbroek 			 (int)ddns_cb->rev_name.len,
1317*83ee113eSDavid van Moolenbroek 			 (const char *)ddns_cb->rev_name.data);
1318*83ee113eSDavid van Moolenbroek 		/* fall through */
1319*83ee113eSDavid van Moolenbroek 	case DNS_R_NXRRSET:
1320*83ee113eSDavid van Moolenbroek 	case DNS_R_NXDOMAIN:
1321*83ee113eSDavid van Moolenbroek 		/* No entry is the same as success.
1322*83ee113eSDavid van Moolenbroek 		 * Remove the information from the lease and
1323*83ee113eSDavid van Moolenbroek 		 * continue with any next step */
1324*83ee113eSDavid van Moolenbroek 		ddns_update_lease_text(ddns_cb, NULL);
1325*83ee113eSDavid van Moolenbroek 
1326*83ee113eSDavid van Moolenbroek 		/* trigger any add operation */
1327*83ee113eSDavid van Moolenbroek 		result = ISC_R_SUCCESS;
1328*83ee113eSDavid van Moolenbroek #if defined (DEBUG_DNS_UPDATES)
1329*83ee113eSDavid van Moolenbroek 		log_info("DDNS: removed map or no reverse map to remove %.*s",
1330*83ee113eSDavid van Moolenbroek 			 (int)ddns_cb->rev_name.len,
1331*83ee113eSDavid van Moolenbroek 			 (const char *)ddns_cb->rev_name.data);
1332*83ee113eSDavid van Moolenbroek #endif
1333*83ee113eSDavid van Moolenbroek 		break;
1334*83ee113eSDavid van Moolenbroek 
1335*83ee113eSDavid van Moolenbroek 	default:
1336*83ee113eSDavid van Moolenbroek 		log_error("Can't remove reverse map on %.*s: %s",
1337*83ee113eSDavid van Moolenbroek 			  (int)ddns_cb->rev_name.len,
1338*83ee113eSDavid van Moolenbroek 			  (const char *)ddns_cb->rev_name.data,
1339*83ee113eSDavid van Moolenbroek 			  isc_result_totext (eresult));
1340*83ee113eSDavid van Moolenbroek 		break;
1341*83ee113eSDavid van Moolenbroek 	}
1342*83ee113eSDavid van Moolenbroek 
1343*83ee113eSDavid van Moolenbroek 	ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1344*83ee113eSDavid van Moolenbroek 	ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, result);
1345*83ee113eSDavid van Moolenbroek 	ddns_cb_free(ddns_cb, MDL);
1346*83ee113eSDavid van Moolenbroek 	return;
1347*83ee113eSDavid van Moolenbroek }
1348*83ee113eSDavid van Moolenbroek 
1349*83ee113eSDavid van Moolenbroek 
1350*83ee113eSDavid van Moolenbroek /*
1351*83ee113eSDavid van Moolenbroek  * If the first query succeeds, the updater can conclude that it
1352*83ee113eSDavid van Moolenbroek  * has added a new name whose only RRs are the A and DHCID RR records.
1353*83ee113eSDavid van Moolenbroek  * The A RR update is now complete (and a client updater is finished,
1354*83ee113eSDavid van Moolenbroek  * while a server might proceed to perform a PTR RR update).
1355*83ee113eSDavid van Moolenbroek  *   -- "Interaction between DHCP and DNS"
1356*83ee113eSDavid van Moolenbroek  *
1357*83ee113eSDavid van Moolenbroek  * If the second query succeeds, the updater can conclude that the current
1358*83ee113eSDavid van Moolenbroek  * client was the last client associated with the domain name, and that
1359*83ee113eSDavid van Moolenbroek  * the name now contains the updated A RR. The A RR update is now
1360*83ee113eSDavid van Moolenbroek  * complete (and a client updater is finished, while a server would
1361*83ee113eSDavid van Moolenbroek  * then proceed to perform a PTR RR update).
1362*83ee113eSDavid van Moolenbroek  *   -- "Interaction between DHCP and DNS"
1363*83ee113eSDavid van Moolenbroek  *
1364*83ee113eSDavid van Moolenbroek  * If the second query fails with NXRRSET, the updater must conclude
1365*83ee113eSDavid van Moolenbroek  * that the client's desired name is in use by another host.  At this
1366*83ee113eSDavid van Moolenbroek  * juncture, the updater can decide (based on some administrative
1367*83ee113eSDavid van Moolenbroek  * configuration outside of the scope of this document) whether to let
1368*83ee113eSDavid van Moolenbroek  * the existing owner of the name keep that name, and to (possibly)
1369*83ee113eSDavid van Moolenbroek  * perform some name disambiguation operation on behalf of the current
1370*83ee113eSDavid van Moolenbroek  * client, or to replace the RRs on the name with RRs that represent
1371*83ee113eSDavid van Moolenbroek  * the current client. If the configured policy allows replacement of
1372*83ee113eSDavid van Moolenbroek  * existing records, the updater submits a query that deletes the
1373*83ee113eSDavid van Moolenbroek  * existing A RR and the existing DHCID RR, adding A and DHCID RRs that
1374*83ee113eSDavid van Moolenbroek  * represent the IP address and client-identity of the new client.
1375*83ee113eSDavid van Moolenbroek  *   -- "Interaction between DHCP and DNS"
1376*83ee113eSDavid van Moolenbroek  */
1377*83ee113eSDavid van Moolenbroek 
1378*83ee113eSDavid van Moolenbroek static void
ddns_fwd_srv_add2(dhcp_ddns_cb_t * ddns_cb,isc_result_t eresult)1379*83ee113eSDavid van Moolenbroek ddns_fwd_srv_add2(dhcp_ddns_cb_t *ddns_cb,
1380*83ee113eSDavid van Moolenbroek 		  isc_result_t    eresult)
1381*83ee113eSDavid van Moolenbroek {
1382*83ee113eSDavid van Moolenbroek 	isc_result_t result;
1383*83ee113eSDavid van Moolenbroek 	const char *logstr = NULL;
1384*83ee113eSDavid van Moolenbroek 	char ddns_address[MAX_ADDRESS_STRING_LEN];
1385*83ee113eSDavid van Moolenbroek 
1386*83ee113eSDavid van Moolenbroek 	/* Construct a printable form of the address for logging */
1387*83ee113eSDavid van Moolenbroek 	strcpy(ddns_address, piaddr(ddns_cb->address));
1388*83ee113eSDavid van Moolenbroek 
1389*83ee113eSDavid van Moolenbroek 	switch(eresult) {
1390*83ee113eSDavid van Moolenbroek 	case ISC_R_SUCCESS:
1391*83ee113eSDavid van Moolenbroek 		log_info("Added new forward map from %.*s to %s",
1392*83ee113eSDavid van Moolenbroek 			 (int)ddns_cb->fwd_name.len,
1393*83ee113eSDavid van Moolenbroek 			 (const char *)ddns_cb->fwd_name.data,
1394*83ee113eSDavid van Moolenbroek 			 ddns_address);
1395*83ee113eSDavid van Moolenbroek 
1396*83ee113eSDavid van Moolenbroek 		ddns_update_lease_text(ddns_cb, NULL);
1397*83ee113eSDavid van Moolenbroek 
1398*83ee113eSDavid van Moolenbroek 		if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1399*83ee113eSDavid van Moolenbroek 			/* if we have zone information get rid of it */
1400*83ee113eSDavid van Moolenbroek 			if (ddns_cb->zone != NULL) {
1401*83ee113eSDavid van Moolenbroek 				ddns_cb_forget_zone(ddns_cb);
1402*83ee113eSDavid van Moolenbroek 			}
1403*83ee113eSDavid van Moolenbroek 
1404*83ee113eSDavid van Moolenbroek 			ddns_cb->state = DDNS_STATE_ADD_PTR;
1405*83ee113eSDavid van Moolenbroek 			ddns_cb->cur_func = ddns_ptr_add;
1406*83ee113eSDavid van Moolenbroek 
1407*83ee113eSDavid van Moolenbroek 			result = ddns_modify_ptr(ddns_cb, MDL);
1408*83ee113eSDavid van Moolenbroek 			if (result == ISC_R_SUCCESS) {
1409*83ee113eSDavid van Moolenbroek 				return;
1410*83ee113eSDavid van Moolenbroek 			}
1411*83ee113eSDavid van Moolenbroek 		}
1412*83ee113eSDavid van Moolenbroek 		break;
1413*83ee113eSDavid van Moolenbroek 
1414*83ee113eSDavid van Moolenbroek 	case DNS_R_YXRRSET:
1415*83ee113eSDavid van Moolenbroek 	case DNS_R_YXDOMAIN:
1416*83ee113eSDavid van Moolenbroek 		logstr = "DHCID mismatch, belongs to another client.";
1417*83ee113eSDavid van Moolenbroek 		break;
1418*83ee113eSDavid van Moolenbroek 
1419*83ee113eSDavid van Moolenbroek 	case DNS_R_NXRRSET:
1420*83ee113eSDavid van Moolenbroek 	case DNS_R_NXDOMAIN:
1421*83ee113eSDavid van Moolenbroek 		logstr = "Has an address record but no DHCID, not mine.";
1422*83ee113eSDavid van Moolenbroek 		break;
1423*83ee113eSDavid van Moolenbroek 
1424*83ee113eSDavid van Moolenbroek 	default:
1425*83ee113eSDavid van Moolenbroek 		logstr = isc_result_totext(eresult);
1426*83ee113eSDavid van Moolenbroek 		break;
1427*83ee113eSDavid van Moolenbroek 	}
1428*83ee113eSDavid van Moolenbroek 
1429*83ee113eSDavid van Moolenbroek 	if (logstr != NULL) {
1430*83ee113eSDavid van Moolenbroek 		log_error("Forward map from %.*s to %s FAILED: %s",
1431*83ee113eSDavid van Moolenbroek 			  (int)ddns_cb->fwd_name.len,
1432*83ee113eSDavid van Moolenbroek 			  (const char *)ddns_cb->fwd_name.data,
1433*83ee113eSDavid van Moolenbroek 			  ddns_address, logstr);
1434*83ee113eSDavid van Moolenbroek 	}
1435*83ee113eSDavid van Moolenbroek 
1436*83ee113eSDavid van Moolenbroek 	ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1437*83ee113eSDavid van Moolenbroek 	ddns_cb_free(ddns_cb, MDL);
1438*83ee113eSDavid van Moolenbroek 	/*
1439*83ee113eSDavid van Moolenbroek 	 * A single DDNS operation may require several calls depending on
1440*83ee113eSDavid van Moolenbroek 	 * the current state as the prerequisites for the first message
1441*83ee113eSDavid van Moolenbroek 	 * may not succeed requiring a second operation and potentially
1442*83ee113eSDavid van Moolenbroek 	 * a ptr operation after that.  The commit_leases operation is
1443*83ee113eSDavid van Moolenbroek 	 * invoked at the end of this set of operations in order to require
1444*83ee113eSDavid van Moolenbroek 	 * a single write for all of the changes.  We call commit_leases
1445*83ee113eSDavid van Moolenbroek 	 * here rather than immediately after the call to update the lease
1446*83ee113eSDavid van Moolenbroek 	 * text in order to save any previously written data.
1447*83ee113eSDavid van Moolenbroek 	 */
1448*83ee113eSDavid van Moolenbroek 	commit_leases();
1449*83ee113eSDavid van Moolenbroek 	return;
1450*83ee113eSDavid van Moolenbroek }
1451*83ee113eSDavid van Moolenbroek 
1452*83ee113eSDavid van Moolenbroek static void
ddns_fwd_srv_add1(dhcp_ddns_cb_t * ddns_cb,isc_result_t eresult)1453*83ee113eSDavid van Moolenbroek ddns_fwd_srv_add1(dhcp_ddns_cb_t *ddns_cb,
1454*83ee113eSDavid van Moolenbroek 		  isc_result_t    eresult)
1455*83ee113eSDavid van Moolenbroek {
1456*83ee113eSDavid van Moolenbroek 	isc_result_t result;
1457*83ee113eSDavid van Moolenbroek 	char ddns_address[MAX_ADDRESS_STRING_LEN];
1458*83ee113eSDavid van Moolenbroek 
1459*83ee113eSDavid van Moolenbroek 	/* Construct a printable form of the address for logging */
1460*83ee113eSDavid van Moolenbroek 	strcpy(ddns_address, piaddr(ddns_cb->address));
1461*83ee113eSDavid van Moolenbroek 
1462*83ee113eSDavid van Moolenbroek 	switch(eresult) {
1463*83ee113eSDavid van Moolenbroek 	case ISC_R_SUCCESS:
1464*83ee113eSDavid van Moolenbroek 		log_info ("Added new forward map from %.*s to %s",
1465*83ee113eSDavid van Moolenbroek 			  (int)ddns_cb->fwd_name.len,
1466*83ee113eSDavid van Moolenbroek 			  (const char *)ddns_cb->fwd_name.data,
1467*83ee113eSDavid van Moolenbroek 			  ddns_address);
1468*83ee113eSDavid van Moolenbroek 
1469*83ee113eSDavid van Moolenbroek 		ddns_update_lease_text(ddns_cb, NULL);
1470*83ee113eSDavid van Moolenbroek 
1471*83ee113eSDavid van Moolenbroek 		if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1472*83ee113eSDavid van Moolenbroek 			/* if we have zone information get rid of it */
1473*83ee113eSDavid van Moolenbroek 			if (ddns_cb->zone != NULL) {
1474*83ee113eSDavid van Moolenbroek 				ddns_cb_forget_zone(ddns_cb);
1475*83ee113eSDavid van Moolenbroek 			}
1476*83ee113eSDavid van Moolenbroek 
1477*83ee113eSDavid van Moolenbroek 			ddns_cb->state = DDNS_STATE_ADD_PTR;
1478*83ee113eSDavid van Moolenbroek 			ddns_cb->cur_func = ddns_ptr_add;
1479*83ee113eSDavid van Moolenbroek 
1480*83ee113eSDavid van Moolenbroek 			result = ddns_modify_ptr(ddns_cb, MDL);
1481*83ee113eSDavid van Moolenbroek 			if (result == ISC_R_SUCCESS) {
1482*83ee113eSDavid van Moolenbroek 				return;
1483*83ee113eSDavid van Moolenbroek 			}
1484*83ee113eSDavid van Moolenbroek 		}
1485*83ee113eSDavid van Moolenbroek 		break;
1486*83ee113eSDavid van Moolenbroek 
1487*83ee113eSDavid van Moolenbroek 	case DNS_R_YXDOMAIN:
1488*83ee113eSDavid van Moolenbroek 		/* we can reuse the zone information */
1489*83ee113eSDavid van Moolenbroek 		ddns_cb->state = DDNS_STATE_ADD_FW_YXDHCID;
1490*83ee113eSDavid van Moolenbroek 		ddns_cb->cur_func = ddns_fwd_srv_add2;
1491*83ee113eSDavid van Moolenbroek 
1492*83ee113eSDavid van Moolenbroek 		result = ddns_modify_fwd(ddns_cb, MDL);
1493*83ee113eSDavid van Moolenbroek 		if (result == ISC_R_SUCCESS) {
1494*83ee113eSDavid van Moolenbroek 			return;
1495*83ee113eSDavid van Moolenbroek 		}
1496*83ee113eSDavid van Moolenbroek 		break;
1497*83ee113eSDavid van Moolenbroek 
1498*83ee113eSDavid van Moolenbroek 	default:
1499*83ee113eSDavid van Moolenbroek 		log_error ("Unable to add forward map from %.*s to %s: %s",
1500*83ee113eSDavid van Moolenbroek 			   (int)ddns_cb->fwd_name.len,
1501*83ee113eSDavid van Moolenbroek 			   (const char *)ddns_cb->fwd_name.data,
1502*83ee113eSDavid van Moolenbroek 			   ddns_address,
1503*83ee113eSDavid van Moolenbroek 			   isc_result_totext (eresult));
1504*83ee113eSDavid van Moolenbroek 		break;
1505*83ee113eSDavid van Moolenbroek 	}
1506*83ee113eSDavid van Moolenbroek 
1507*83ee113eSDavid van Moolenbroek 	ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1508*83ee113eSDavid van Moolenbroek 	ddns_cb_free(ddns_cb, MDL);
1509*83ee113eSDavid van Moolenbroek 	/*
1510*83ee113eSDavid van Moolenbroek 	 * A single DDNS operation may require several calls depending on
1511*83ee113eSDavid van Moolenbroek 	 * the current state as the prerequisites for the first message
1512*83ee113eSDavid van Moolenbroek 	 * may not succeed requiring a second operation and potentially
1513*83ee113eSDavid van Moolenbroek 	 * a ptr operation after that.  The commit_leases operation is
1514*83ee113eSDavid van Moolenbroek 	 * invoked at the end of this set of operations in order to require
1515*83ee113eSDavid van Moolenbroek 	 * a single write for all of the changes.  We call commit_leases
1516*83ee113eSDavid van Moolenbroek 	 * here rather than immediately after the call to update the lease
1517*83ee113eSDavid van Moolenbroek 	 * text in order to save any previously written data.
1518*83ee113eSDavid van Moolenbroek 	 */
1519*83ee113eSDavid van Moolenbroek 	commit_leases();
1520*83ee113eSDavid van Moolenbroek 	return;
1521*83ee113eSDavid van Moolenbroek }
1522*83ee113eSDavid van Moolenbroek 
1523*83ee113eSDavid van Moolenbroek static void
ddns_fwd_srv_connector(struct lease * lease,struct iasubopt * lease6,struct binding_scope ** inscope,dhcp_ddns_cb_t * ddns_cb,isc_result_t eresult)1524*83ee113eSDavid van Moolenbroek ddns_fwd_srv_connector(struct lease          *lease,
1525*83ee113eSDavid van Moolenbroek 		       struct iasubopt       *lease6,
1526*83ee113eSDavid van Moolenbroek 		       struct binding_scope **inscope,
1527*83ee113eSDavid van Moolenbroek 		       dhcp_ddns_cb_t        *ddns_cb,
1528*83ee113eSDavid van Moolenbroek 		       isc_result_t           eresult)
1529*83ee113eSDavid van Moolenbroek {
1530*83ee113eSDavid van Moolenbroek 	isc_result_t result = ISC_R_FAILURE;
1531*83ee113eSDavid van Moolenbroek 
1532*83ee113eSDavid van Moolenbroek 	if (ddns_cb == NULL) {
1533*83ee113eSDavid van Moolenbroek 		/* nothing to do */
1534*83ee113eSDavid van Moolenbroek 		return;
1535*83ee113eSDavid van Moolenbroek 	}
1536*83ee113eSDavid van Moolenbroek 
1537*83ee113eSDavid van Moolenbroek 	if (eresult == ISC_R_SUCCESS) {
1538*83ee113eSDavid van Moolenbroek 		/*
1539*83ee113eSDavid van Moolenbroek 		 * If we have updates dispatch as appropriate,
1540*83ee113eSDavid van Moolenbroek 		 * if not do FQDN binding if desired.
1541*83ee113eSDavid van Moolenbroek 		 */
1542*83ee113eSDavid van Moolenbroek 
1543*83ee113eSDavid van Moolenbroek 		if (ddns_cb->flags & DDNS_UPDATE_ADDR) {
1544*83ee113eSDavid van Moolenbroek 			ddns_cb->state    = DDNS_STATE_ADD_FW_NXDOMAIN;
1545*83ee113eSDavid van Moolenbroek 			ddns_cb->cur_func = ddns_fwd_srv_add1;
1546*83ee113eSDavid van Moolenbroek 			result = ddns_modify_fwd(ddns_cb, MDL);
1547*83ee113eSDavid van Moolenbroek 		} else if ((ddns_cb->flags & DDNS_UPDATE_PTR) &&
1548*83ee113eSDavid van Moolenbroek 			 (ddns_cb->rev_name.len != 0)) {
1549*83ee113eSDavid van Moolenbroek 			ddns_cb->state    = DDNS_STATE_ADD_PTR;
1550*83ee113eSDavid van Moolenbroek 			ddns_cb->cur_func = ddns_ptr_add;
1551*83ee113eSDavid van Moolenbroek 			result = ddns_modify_ptr(ddns_cb, MDL);
1552*83ee113eSDavid van Moolenbroek 		} else {
1553*83ee113eSDavid van Moolenbroek 			ddns_update_lease_text(ddns_cb, inscope);
1554*83ee113eSDavid van Moolenbroek 		}
1555*83ee113eSDavid van Moolenbroek 	}
1556*83ee113eSDavid van Moolenbroek 
1557*83ee113eSDavid van Moolenbroek 	if (result == ISC_R_SUCCESS) {
1558*83ee113eSDavid van Moolenbroek 		ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb, MDL);
1559*83ee113eSDavid van Moolenbroek 	} else {
1560*83ee113eSDavid van Moolenbroek 		ddns_cb_free(ddns_cb, MDL);
1561*83ee113eSDavid van Moolenbroek 	}
1562*83ee113eSDavid van Moolenbroek 
1563*83ee113eSDavid van Moolenbroek 	return;
1564*83ee113eSDavid van Moolenbroek }
1565*83ee113eSDavid van Moolenbroek 
1566*83ee113eSDavid van Moolenbroek /*
1567*83ee113eSDavid van Moolenbroek  * If the first query fails, the updater MUST NOT delete the DNS name.  It
1568*83ee113eSDavid van Moolenbroek  * may be that the host whose lease on the server has expired has moved
1569*83ee113eSDavid van Moolenbroek  * to another network and obtained a lease from a different server,
1570*83ee113eSDavid van Moolenbroek  * which has caused the client's A RR to be replaced. It may also be
1571*83ee113eSDavid van Moolenbroek  * that some other client has been configured with a name that matches
1572*83ee113eSDavid van Moolenbroek  * the name of the DHCP client, and the policy was that the last client
1573*83ee113eSDavid van Moolenbroek  * to specify the name would get the name.  In this case, the DHCID RR
1574*83ee113eSDavid van Moolenbroek  * will no longer match the updater's notion of the client-identity of
1575*83ee113eSDavid van Moolenbroek  * the host pointed to by the DNS name.
1576*83ee113eSDavid van Moolenbroek  *   -- "Interaction between DHCP and DNS"
1577*83ee113eSDavid van Moolenbroek  */
1578*83ee113eSDavid van Moolenbroek 
1579*83ee113eSDavid van Moolenbroek static void
ddns_fwd_srv_rem2(dhcp_ddns_cb_t * ddns_cb,isc_result_t eresult)1580*83ee113eSDavid van Moolenbroek ddns_fwd_srv_rem2(dhcp_ddns_cb_t *ddns_cb,
1581*83ee113eSDavid van Moolenbroek 		  isc_result_t    eresult)
1582*83ee113eSDavid van Moolenbroek {
1583*83ee113eSDavid van Moolenbroek 	if (eresult == ISC_R_SUCCESS) {
1584*83ee113eSDavid van Moolenbroek 		ddns_update_lease_text(ddns_cb, NULL);
1585*83ee113eSDavid van Moolenbroek 
1586*83ee113eSDavid van Moolenbroek 		/* Do the next operation */
1587*83ee113eSDavid van Moolenbroek 		if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1588*83ee113eSDavid van Moolenbroek 			/* if we have zone information get rid of it */
1589*83ee113eSDavid van Moolenbroek 			if (ddns_cb->zone != NULL) {
1590*83ee113eSDavid van Moolenbroek 				ddns_cb_forget_zone(ddns_cb);
1591*83ee113eSDavid van Moolenbroek 			}
1592*83ee113eSDavid van Moolenbroek 
1593*83ee113eSDavid van Moolenbroek 			ddns_cb->state = DDNS_STATE_REM_PTR;
1594*83ee113eSDavid van Moolenbroek 			ddns_cb->cur_func = ddns_ptr_remove;
1595*83ee113eSDavid van Moolenbroek 
1596*83ee113eSDavid van Moolenbroek 			eresult = ddns_modify_ptr(ddns_cb, MDL);
1597*83ee113eSDavid van Moolenbroek 			if (eresult == ISC_R_SUCCESS) {
1598*83ee113eSDavid van Moolenbroek 				return;
1599*83ee113eSDavid van Moolenbroek 			}
1600*83ee113eSDavid van Moolenbroek 		}
1601*83ee113eSDavid van Moolenbroek 	}
1602*83ee113eSDavid van Moolenbroek 
1603*83ee113eSDavid van Moolenbroek 	ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1604*83ee113eSDavid van Moolenbroek 	ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult);
1605*83ee113eSDavid van Moolenbroek 	ddns_cb_free(ddns_cb, MDL);
1606*83ee113eSDavid van Moolenbroek 	return;
1607*83ee113eSDavid van Moolenbroek }
1608*83ee113eSDavid van Moolenbroek 
1609*83ee113eSDavid van Moolenbroek 
1610*83ee113eSDavid van Moolenbroek /*
1611*83ee113eSDavid van Moolenbroek  * First action routine when trying to remove a fwd
1612*83ee113eSDavid van Moolenbroek  * this will be called after the ddns queries have completed
1613*83ee113eSDavid van Moolenbroek  * if we succeeded in removing the fwd we go to the next step (if any)
1614*83ee113eSDavid van Moolenbroek  * if not we cleanup and leave.
1615*83ee113eSDavid van Moolenbroek  */
1616*83ee113eSDavid van Moolenbroek 
1617*83ee113eSDavid van Moolenbroek static void
ddns_fwd_srv_rem1(dhcp_ddns_cb_t * ddns_cb,isc_result_t eresult)1618*83ee113eSDavid van Moolenbroek ddns_fwd_srv_rem1(dhcp_ddns_cb_t *ddns_cb,
1619*83ee113eSDavid van Moolenbroek 		  isc_result_t    eresult)
1620*83ee113eSDavid van Moolenbroek {
1621*83ee113eSDavid van Moolenbroek 	isc_result_t result = eresult;
1622*83ee113eSDavid van Moolenbroek 	char ddns_address[MAX_ADDRESS_STRING_LEN];
1623*83ee113eSDavid van Moolenbroek 
1624*83ee113eSDavid van Moolenbroek 	switch(eresult) {
1625*83ee113eSDavid van Moolenbroek 	case ISC_R_SUCCESS:
1626*83ee113eSDavid van Moolenbroek 		/* Construct a printable form of the address for logging */
1627*83ee113eSDavid van Moolenbroek 		strcpy(ddns_address, piaddr(ddns_cb->address));
1628*83ee113eSDavid van Moolenbroek 		log_info("Removed forward map from %.*s to %s",
1629*83ee113eSDavid van Moolenbroek 			 (int)ddns_cb->fwd_name.len,
1630*83ee113eSDavid van Moolenbroek 			 (const char*)ddns_cb->fwd_name.data,
1631*83ee113eSDavid van Moolenbroek 			 ddns_address);
1632*83ee113eSDavid van Moolenbroek 
1633*83ee113eSDavid van Moolenbroek 		/* Do the second step of the FWD removal */
1634*83ee113eSDavid van Moolenbroek 		ddns_cb->state    = DDNS_STATE_REM_FW_NXRR;
1635*83ee113eSDavid van Moolenbroek 		ddns_cb->cur_func = ddns_fwd_srv_rem2;
1636*83ee113eSDavid van Moolenbroek 		result = ddns_modify_fwd(ddns_cb, MDL);
1637*83ee113eSDavid van Moolenbroek 		if (result == ISC_R_SUCCESS) {
1638*83ee113eSDavid van Moolenbroek 			return;
1639*83ee113eSDavid van Moolenbroek 		}
1640*83ee113eSDavid van Moolenbroek 		break;
1641*83ee113eSDavid van Moolenbroek 
1642*83ee113eSDavid van Moolenbroek 	case DNS_R_NXRRSET:
1643*83ee113eSDavid van Moolenbroek 	case DNS_R_NXDOMAIN:
1644*83ee113eSDavid van Moolenbroek 		ddns_update_lease_text(ddns_cb, NULL);
1645*83ee113eSDavid van Moolenbroek 
1646*83ee113eSDavid van Moolenbroek #if defined (DEBUG_DNS_UPDATES)
1647*83ee113eSDavid van Moolenbroek 		log_info("DDNS: no forward map to remove. %p", ddns_cb);
1648*83ee113eSDavid van Moolenbroek #endif
1649*83ee113eSDavid van Moolenbroek 
1650*83ee113eSDavid van Moolenbroek 		/* Do the next operation */
1651*83ee113eSDavid van Moolenbroek 		if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1652*83ee113eSDavid van Moolenbroek 			/* if we have zone information get rid of it */
1653*83ee113eSDavid van Moolenbroek 			if (ddns_cb->zone != NULL) {
1654*83ee113eSDavid van Moolenbroek 				ddns_cb_forget_zone(ddns_cb);
1655*83ee113eSDavid van Moolenbroek 			}
1656*83ee113eSDavid van Moolenbroek 
1657*83ee113eSDavid van Moolenbroek 			ddns_cb->state    = DDNS_STATE_REM_PTR;
1658*83ee113eSDavid van Moolenbroek 			ddns_cb->cur_func = ddns_ptr_remove;
1659*83ee113eSDavid van Moolenbroek 
1660*83ee113eSDavid van Moolenbroek 			result = ddns_modify_ptr(ddns_cb, MDL);
1661*83ee113eSDavid van Moolenbroek 			if (result == ISC_R_SUCCESS) {
1662*83ee113eSDavid van Moolenbroek 				return;
1663*83ee113eSDavid van Moolenbroek 			}
1664*83ee113eSDavid van Moolenbroek 		}
1665*83ee113eSDavid van Moolenbroek 		else {
1666*83ee113eSDavid van Moolenbroek 			/* Trigger the add operation */
1667*83ee113eSDavid van Moolenbroek 			eresult = ISC_R_SUCCESS;
1668*83ee113eSDavid van Moolenbroek 		}
1669*83ee113eSDavid van Moolenbroek 		break;
1670*83ee113eSDavid van Moolenbroek 
1671*83ee113eSDavid van Moolenbroek 	default:
1672*83ee113eSDavid van Moolenbroek 		break;
1673*83ee113eSDavid van Moolenbroek 	}
1674*83ee113eSDavid van Moolenbroek 
1675*83ee113eSDavid van Moolenbroek 	ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1676*83ee113eSDavid van Moolenbroek 	ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult);
1677*83ee113eSDavid van Moolenbroek 	ddns_cb_free(ddns_cb, MDL);
1678*83ee113eSDavid van Moolenbroek }
1679*83ee113eSDavid van Moolenbroek 
1680*83ee113eSDavid van Moolenbroek /*%<
1681*83ee113eSDavid van Moolenbroek  * Remove relevant entries from DNS.
1682*83ee113eSDavid van Moolenbroek  *
1683*83ee113eSDavid van Moolenbroek  * \li lease  - lease to start with if this is for v4
1684*83ee113eSDavid van Moolenbroek  *
1685*83ee113eSDavid van Moolenbroek  * \li lease6 - lease to start with if this is for v6
1686*83ee113eSDavid van Moolenbroek  *
1687*83ee113eSDavid van Moolenbroek  * \li add_ddns_cb - control block for additional DDNS work.  This
1688*83ee113eSDavid van Moolenbroek  *     is used when the code is going to add a DDNS entry after removing
1689*83ee113eSDavid van Moolenbroek  *     the current entry.
1690*83ee113eSDavid van Moolenbroek  *
1691*83ee113eSDavid van Moolenbroek  * \li active - indication about the status of the lease. It is
1692*83ee113eSDavid van Moolenbroek  *     ISC_TRUE if the lease is still active, and FALSE if the lease
1693*83ee113eSDavid van Moolenbroek  *     is inactive.  This is used to indicate if the lease is inactive or going
1694*83ee113eSDavid van Moolenbroek  *     to inactive so we can avoid trying to update the lease with cb pointers
1695*83ee113eSDavid van Moolenbroek  *     and text information if it isn't useful.
1696*83ee113eSDavid van Moolenbroek  *
1697*83ee113eSDavid van Moolenbroek  * Returns
1698*83ee113eSDavid van Moolenbroek  * \li #ISC_R_FAILURE - badness occurred and we weren't able to do what was wanted
1699*83ee113eSDavid van Moolenbroek  * \li #ISC_R_SUCCESS - we were able to do stuff but it's in progress
1700*83ee113eSDavid van Moolenbroek  *
1701*83ee113eSDavid van Moolenbroek  * in both cases any additional block has been passed on to it's handler
1702*83ee113eSDavid van Moolenbroek  */
1703*83ee113eSDavid van Moolenbroek 
1704*83ee113eSDavid van Moolenbroek isc_result_t
ddns_removals(struct lease * lease,struct iasubopt * lease6,dhcp_ddns_cb_t * add_ddns_cb,isc_boolean_t active)1705*83ee113eSDavid van Moolenbroek ddns_removals(struct lease    *lease,
1706*83ee113eSDavid van Moolenbroek 	      struct iasubopt *lease6,
1707*83ee113eSDavid van Moolenbroek 	      dhcp_ddns_cb_t  *add_ddns_cb,
1708*83ee113eSDavid van Moolenbroek 	      isc_boolean_t    active)
1709*83ee113eSDavid van Moolenbroek {
1710*83ee113eSDavid van Moolenbroek 	isc_result_t rcode, execute_add = ISC_R_FAILURE;
1711*83ee113eSDavid van Moolenbroek 	struct binding_scope **scope = NULL;
1712*83ee113eSDavid van Moolenbroek 	isc_result_t result = ISC_R_FAILURE;
1713*83ee113eSDavid van Moolenbroek 	dhcp_ddns_cb_t        *ddns_cb = NULL;
1714*83ee113eSDavid van Moolenbroek 	struct data_string     leaseid;
1715*83ee113eSDavid van Moolenbroek 
1716*83ee113eSDavid van Moolenbroek 	/*
1717*83ee113eSDavid van Moolenbroek 	 * See if we need to cancel an outstanding request.  Mostly this is
1718*83ee113eSDavid van Moolenbroek 	 * used to handle the case where this routine is called twice for
1719*83ee113eSDavid van Moolenbroek 	 * the same release or abandon event.
1720*83ee113eSDavid van Moolenbroek 	 *
1721*83ee113eSDavid van Moolenbroek 	 * When called from the dns code as part of an update request
1722*83ee113eSDavid van Moolenbroek 	 * (add_ddns_cb != NULL) any outstanding requests will have already
1723*83ee113eSDavid van Moolenbroek 	 * been cancelled.
1724*83ee113eSDavid van Moolenbroek 	 *
1725*83ee113eSDavid van Moolenbroek 	 * If the new request is just a removal and we have an outstanding
1726*83ee113eSDavid van Moolenbroek 	 * request we have several options:
1727*83ee113eSDavid van Moolenbroek 	 *
1728*83ee113eSDavid van Moolenbroek 	 * - we are doing an update or we are doing a removal and the active
1729*83ee113eSDavid van Moolenbroek 	 * flag has changed from TRUE to FALSE.  In these cases we  need to
1730*83ee113eSDavid van Moolenbroek 	 * cancel the old request and start the new one.
1731*83ee113eSDavid van Moolenbroek 	 *
1732*83ee113eSDavid van Moolenbroek 	 * - other wise we are doing a removal with the active flag unchanged.
1733*83ee113eSDavid van Moolenbroek 	 * In this case we can let the current removal continue and do not need
1734*83ee113eSDavid van Moolenbroek 	 * to start a new one.  If the old request included an update to be
1735*83ee113eSDavid van Moolenbroek 	 * done after the removal we need to kill the update part of the
1736*83ee113eSDavid van Moolenbroek 	 * request.
1737*83ee113eSDavid van Moolenbroek 	 */
1738*83ee113eSDavid van Moolenbroek 
1739*83ee113eSDavid van Moolenbroek 	if (add_ddns_cb == NULL) {
1740*83ee113eSDavid van Moolenbroek 		if ((lease != NULL) && (lease->ddns_cb != NULL)) {
1741*83ee113eSDavid van Moolenbroek 			ddns_cb = lease->ddns_cb;
1742*83ee113eSDavid van Moolenbroek 
1743*83ee113eSDavid van Moolenbroek 			/*
1744*83ee113eSDavid van Moolenbroek 			 * Is the old request an update or did the
1745*83ee113eSDavid van Moolenbroek 			 * the active flag change?
1746*83ee113eSDavid van Moolenbroek 			 */
1747*83ee113eSDavid van Moolenbroek 			if (((ddns_cb->state == DDNS_STATE_ADD_PTR) ||
1748*83ee113eSDavid van Moolenbroek 			     (ddns_cb->state == DDNS_STATE_ADD_FW_NXDOMAIN) ||
1749*83ee113eSDavid van Moolenbroek 			     (ddns_cb->state == DDNS_STATE_ADD_FW_YXDHCID)) ||
1750*83ee113eSDavid van Moolenbroek 			    ((active == ISC_FALSE) &&
1751*83ee113eSDavid van Moolenbroek 			     ((ddns_cb->flags & DDNS_ACTIVE_LEASE) != 0))) {
1752*83ee113eSDavid van Moolenbroek 				/* Cancel the current request */
1753*83ee113eSDavid van Moolenbroek 				ddns_cancel(lease->ddns_cb, MDL);
1754*83ee113eSDavid van Moolenbroek 				lease->ddns_cb = NULL;
1755*83ee113eSDavid van Moolenbroek 			} else {
1756*83ee113eSDavid van Moolenbroek 				/* Remvoval, check and remove updates */
1757*83ee113eSDavid van Moolenbroek 				if (ddns_cb->next_op != NULL) {
1758*83ee113eSDavid van Moolenbroek 					ddns_cb_free(ddns_cb->next_op, MDL);
1759*83ee113eSDavid van Moolenbroek 					ddns_cb->next_op = NULL;
1760*83ee113eSDavid van Moolenbroek 				}
1761*83ee113eSDavid van Moolenbroek #if defined (DEBUG_DNS_UPDATES)
1762*83ee113eSDavid van Moolenbroek 				log_info("DDNS %s(%d): removal already in "
1763*83ee113eSDavid van Moolenbroek 					 "progress new ddns_cb=%p",
1764*83ee113eSDavid van Moolenbroek 					 MDL, ddns_cb);
1765*83ee113eSDavid van Moolenbroek #endif
1766*83ee113eSDavid van Moolenbroek 				return (ISC_R_SUCCESS);
1767*83ee113eSDavid van Moolenbroek 			}
1768*83ee113eSDavid van Moolenbroek 		} else if ((lease6 != NULL) && (lease6->ddns_cb != NULL)) {
1769*83ee113eSDavid van Moolenbroek 			ddns_cb = lease6->ddns_cb;
1770*83ee113eSDavid van Moolenbroek 
1771*83ee113eSDavid van Moolenbroek 			/*
1772*83ee113eSDavid van Moolenbroek 			 * Is the old request an update or did the
1773*83ee113eSDavid van Moolenbroek 			 * the active flag change?
1774*83ee113eSDavid van Moolenbroek 			 */
1775*83ee113eSDavid van Moolenbroek 			if (((ddns_cb->state == DDNS_STATE_ADD_PTR) ||
1776*83ee113eSDavid van Moolenbroek 			     (ddns_cb->state == DDNS_STATE_ADD_FW_NXDOMAIN) ||
1777*83ee113eSDavid van Moolenbroek 			     (ddns_cb->state == DDNS_STATE_ADD_FW_YXDHCID)) ||
1778*83ee113eSDavid van Moolenbroek 			    ((active == ISC_FALSE) &&
1779*83ee113eSDavid van Moolenbroek 			     ((ddns_cb->flags & DDNS_ACTIVE_LEASE) != 0))) {
1780*83ee113eSDavid van Moolenbroek 				/* Cancel the current request */
1781*83ee113eSDavid van Moolenbroek 				ddns_cancel(lease6->ddns_cb, MDL);
1782*83ee113eSDavid van Moolenbroek 				lease6->ddns_cb = NULL;
1783*83ee113eSDavid van Moolenbroek 			} else {
1784*83ee113eSDavid van Moolenbroek 				/* Remvoval, check and remove updates */
1785*83ee113eSDavid van Moolenbroek 				if (ddns_cb->next_op != NULL) {
1786*83ee113eSDavid van Moolenbroek 					ddns_cb_free(ddns_cb->next_op, MDL);
1787*83ee113eSDavid van Moolenbroek 					ddns_cb->next_op = NULL;
1788*83ee113eSDavid van Moolenbroek 				}
1789*83ee113eSDavid van Moolenbroek #if defined (DEBUG_DNS_UPDATES)
1790*83ee113eSDavid van Moolenbroek 				log_info("DDNS %s(%d): removal already in "
1791*83ee113eSDavid van Moolenbroek 					 "progress new ddns_cb=%p",
1792*83ee113eSDavid van Moolenbroek 					 MDL, ddns_cb);
1793*83ee113eSDavid van Moolenbroek #endif
1794*83ee113eSDavid van Moolenbroek 				return (ISC_R_SUCCESS);
1795*83ee113eSDavid van Moolenbroek 			}
1796*83ee113eSDavid van Moolenbroek 		}
1797*83ee113eSDavid van Moolenbroek 		ddns_cb = NULL;
1798*83ee113eSDavid van Moolenbroek 	}
1799*83ee113eSDavid van Moolenbroek 
1800*83ee113eSDavid van Moolenbroek 	/* allocate our control block */
1801*83ee113eSDavid van Moolenbroek 	ddns_cb = ddns_cb_alloc(MDL);
1802*83ee113eSDavid van Moolenbroek 	if (ddns_cb == NULL) {
1803*83ee113eSDavid van Moolenbroek 		goto cleanup;
1804*83ee113eSDavid van Moolenbroek 	}
1805*83ee113eSDavid van Moolenbroek 
1806*83ee113eSDavid van Moolenbroek 	/*
1807*83ee113eSDavid van Moolenbroek 	 * For v4 we flag static leases so we don't try
1808*83ee113eSDavid van Moolenbroek 	 * and manipulate the lease later.  For v6 we don't
1809*83ee113eSDavid van Moolenbroek 	 * get static leases and don't need to flag them.
1810*83ee113eSDavid van Moolenbroek 	 */
1811*83ee113eSDavid van Moolenbroek 	if (lease != NULL) {
1812*83ee113eSDavid van Moolenbroek 		scope = &(lease->scope);
1813*83ee113eSDavid van Moolenbroek 		ddns_cb->address = lease->ip_addr;
1814*83ee113eSDavid van Moolenbroek 		if (lease->flags & STATIC_LEASE)
1815*83ee113eSDavid van Moolenbroek 			ddns_cb->flags |= DDNS_STATIC_LEASE;
1816*83ee113eSDavid van Moolenbroek 	} else if (lease6 != NULL) {
1817*83ee113eSDavid van Moolenbroek 		scope = &(lease6->scope);
1818*83ee113eSDavid van Moolenbroek 		memcpy(&ddns_cb->address.iabuf, lease6->addr.s6_addr, 16);
1819*83ee113eSDavid van Moolenbroek 		ddns_cb->address.len = 16;
1820*83ee113eSDavid van Moolenbroek 	} else
1821*83ee113eSDavid van Moolenbroek 		goto cleanup;
1822*83ee113eSDavid van Moolenbroek 
1823*83ee113eSDavid van Moolenbroek 	/*
1824*83ee113eSDavid van Moolenbroek 	 * Set the flag bit if the lease is active, that is it isn't
1825*83ee113eSDavid van Moolenbroek 	 * expired or released.  This is used to determine if we need
1826*83ee113eSDavid van Moolenbroek 	 * to update the scope information for both v4 and v6 and
1827*83ee113eSDavid van Moolenbroek 	 * the lease information for v6 when the response
1828*83ee113eSDavid van Moolenbroek 	 * from the DNS code is processed.
1829*83ee113eSDavid van Moolenbroek 	 */
1830*83ee113eSDavid van Moolenbroek 	if (active == ISC_TRUE) {
1831*83ee113eSDavid van Moolenbroek 		ddns_cb->flags |= DDNS_ACTIVE_LEASE;
1832*83ee113eSDavid van Moolenbroek 	}
1833*83ee113eSDavid van Moolenbroek 
1834*83ee113eSDavid van Moolenbroek 	/* No scope implies that DDNS has not been performed for this lease. */
1835*83ee113eSDavid van Moolenbroek 	if (*scope == NULL)
1836*83ee113eSDavid van Moolenbroek 		goto cleanup;
1837*83ee113eSDavid van Moolenbroek 
1838*83ee113eSDavid van Moolenbroek 	if ((ddns_update_style != DDNS_UPDATE_STYLE_STANDARD) &&
1839*83ee113eSDavid van Moolenbroek 	    (ddns_update_style != DDNS_UPDATE_STYLE_INTERIM))
1840*83ee113eSDavid van Moolenbroek 		goto cleanup;
1841*83ee113eSDavid van Moolenbroek 
1842*83ee113eSDavid van Moolenbroek 	/* Assume that we are removing both records */
1843*83ee113eSDavid van Moolenbroek 	ddns_cb->flags |= DDNS_UPDATE_ADDR | DDNS_UPDATE_PTR;
1844*83ee113eSDavid van Moolenbroek 
1845*83ee113eSDavid van Moolenbroek 	/* and that we want to do the add call */
1846*83ee113eSDavid van Moolenbroek 	execute_add = ISC_R_SUCCESS;
1847*83ee113eSDavid van Moolenbroek 
1848*83ee113eSDavid van Moolenbroek 	/*
1849*83ee113eSDavid van Moolenbroek 	 * Look up stored names.
1850*83ee113eSDavid van Moolenbroek 	 */
1851*83ee113eSDavid van Moolenbroek 
1852*83ee113eSDavid van Moolenbroek 	/*
1853*83ee113eSDavid van Moolenbroek 	 * Find the fwd name and copy it to the control block.  If we don't
1854*83ee113eSDavid van Moolenbroek 	 * have it we can't delete the fwd record but we can still try to
1855*83ee113eSDavid van Moolenbroek 	 * remove the ptr record and cleanup the lease information if the
1856*83ee113eSDavid van Moolenbroek 	 * client did the fwd update.
1857*83ee113eSDavid van Moolenbroek 	 */
1858*83ee113eSDavid van Moolenbroek 	if (!find_bound_string(&ddns_cb->fwd_name, *scope, "ddns-fwd-name")) {
1859*83ee113eSDavid van Moolenbroek 		/* don't try and delete the A, or do the add */
1860*83ee113eSDavid van Moolenbroek 		ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
1861*83ee113eSDavid van Moolenbroek 		execute_add = ISC_R_FAILURE;
1862*83ee113eSDavid van Moolenbroek 
1863*83ee113eSDavid van Moolenbroek 		/* Check if client did update */
1864*83ee113eSDavid van Moolenbroek 		if (find_bound_string(&ddns_cb->fwd_name, *scope,
1865*83ee113eSDavid van Moolenbroek 				      "ddns-client-fqdn")) {
1866*83ee113eSDavid van Moolenbroek 			ddns_cb->flags |= DDNS_CLIENT_DID_UPDATE;
1867*83ee113eSDavid van Moolenbroek 		}
1868*83ee113eSDavid van Moolenbroek 	}
1869*83ee113eSDavid van Moolenbroek 
1870*83ee113eSDavid van Moolenbroek 	/*
1871*83ee113eSDavid van Moolenbroek 	 * Find the txt or dhcid tag and copy it to the control block.  If we don't
1872*83ee113eSDavid van Moolenbroek 	 * have one this isn't an interim or standard record so we can't delete
1873*83ee113eSDavid van Moolenbroek 	 * the A record using this mechanism but we can delete the ptr record.
1874*83ee113eSDavid van Moolenbroek 	 * In this case we will attempt to do any requested next step.
1875*83ee113eSDavid van Moolenbroek 	 */
1876*83ee113eSDavid van Moolenbroek 	memset(&leaseid, 0, sizeof(leaseid));
1877*83ee113eSDavid van Moolenbroek 	if (find_bound_string (&leaseid, *scope, ddns_standard_tag)) {
1878*83ee113eSDavid van Moolenbroek 		/* We have a standard tag */
1879*83ee113eSDavid van Moolenbroek 		ddns_cb->lease_tag = ddns_standard_tag;
1880*83ee113eSDavid van Moolenbroek 		ddns_cb->dhcid_class = dns_rdatatype_dhcid;
1881*83ee113eSDavid van Moolenbroek 		data_string_copy(&ddns_cb->dhcid, &leaseid, MDL);
1882*83ee113eSDavid van Moolenbroek 		data_string_forget(&leaseid, MDL);
1883*83ee113eSDavid van Moolenbroek 	} else 	if (find_bound_string (&leaseid, *scope, ddns_interim_tag)) {
1884*83ee113eSDavid van Moolenbroek 		/* we have an interim tag */
1885*83ee113eSDavid van Moolenbroek 		ddns_cb->lease_tag = ddns_interim_tag;
1886*83ee113eSDavid van Moolenbroek 		ddns_cb->dhcid_class = dns_rdatatype_txt;
1887*83ee113eSDavid van Moolenbroek 		if (dhcid_fromlease(&ddns_cb->dhcid, &leaseid) !=
1888*83ee113eSDavid van Moolenbroek 		    ISC_R_SUCCESS) {
1889*83ee113eSDavid van Moolenbroek 			/* We couldn't convert the dhcid from the lease
1890*83ee113eSDavid van Moolenbroek 			 * version to the dns version.  We can't delete
1891*83ee113eSDavid van Moolenbroek 			 * the A record but can continue to the ptr
1892*83ee113eSDavid van Moolenbroek 			 */
1893*83ee113eSDavid van Moolenbroek 			ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
1894*83ee113eSDavid van Moolenbroek 		}
1895*83ee113eSDavid van Moolenbroek 		data_string_forget(&leaseid, MDL);
1896*83ee113eSDavid van Moolenbroek 	} else {
1897*83ee113eSDavid van Moolenbroek 		ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
1898*83ee113eSDavid van Moolenbroek 	}
1899*83ee113eSDavid van Moolenbroek 
1900*83ee113eSDavid van Moolenbroek 	/*
1901*83ee113eSDavid van Moolenbroek 	 * Find the rev name and copy it to the control block.  If we don't
1902*83ee113eSDavid van Moolenbroek 	 * have it we can't get rid of it but we can try to remove the fwd
1903*83ee113eSDavid van Moolenbroek 	 * pointer if desired.
1904*83ee113eSDavid van Moolenbroek 	 */
1905*83ee113eSDavid van Moolenbroek 	if (!find_bound_string(&ddns_cb->rev_name, *scope, "ddns-rev-name")) {
1906*83ee113eSDavid van Moolenbroek 		ddns_cb->flags &= ~DDNS_UPDATE_PTR;
1907*83ee113eSDavid van Moolenbroek 	}
1908*83ee113eSDavid van Moolenbroek 
1909*83ee113eSDavid van Moolenbroek 	/*
1910*83ee113eSDavid van Moolenbroek 	 * If we have a second control block for doing an add
1911*83ee113eSDavid van Moolenbroek 	 * after the remove finished attach it to our control block.
1912*83ee113eSDavid van Moolenbroek 	 */
1913*83ee113eSDavid van Moolenbroek 	ddns_cb->next_op = add_ddns_cb;
1914*83ee113eSDavid van Moolenbroek 
1915*83ee113eSDavid van Moolenbroek 	/*
1916*83ee113eSDavid van Moolenbroek 	 * Now that we've collected the information we can try to process it.
1917*83ee113eSDavid van Moolenbroek 	 * If necessary we call an appropriate routine to send a message and
1918*83ee113eSDavid van Moolenbroek 	 * provide it with an action routine to run on the control block given
1919*83ee113eSDavid van Moolenbroek 	 * the results of the message.  We have three entry points from here,
1920*83ee113eSDavid van Moolenbroek 	 * one for removing the A record, the next for removing the PTR and
1921*83ee113eSDavid van Moolenbroek 	 * the third for doing any requested add.
1922*83ee113eSDavid van Moolenbroek 	 */
1923*83ee113eSDavid van Moolenbroek 	if ((ddns_cb->flags & DDNS_UPDATE_ADDR) != 0) {
1924*83ee113eSDavid van Moolenbroek 		if (ddns_cb->fwd_name.len != 0) {
1925*83ee113eSDavid van Moolenbroek 			ddns_cb->state    = DDNS_STATE_REM_FW_YXDHCID;
1926*83ee113eSDavid van Moolenbroek 			ddns_cb->cur_func = ddns_fwd_srv_rem1;
1927*83ee113eSDavid van Moolenbroek 
1928*83ee113eSDavid van Moolenbroek 			rcode = ddns_modify_fwd(ddns_cb, MDL);
1929*83ee113eSDavid van Moolenbroek 			if (rcode == ISC_R_SUCCESS) {
1930*83ee113eSDavid van Moolenbroek 				ddns_update_lease_ptr(lease, lease6, ddns_cb,
1931*83ee113eSDavid van Moolenbroek 						      ddns_cb, MDL);
1932*83ee113eSDavid van Moolenbroek 				return (ISC_R_SUCCESS);
1933*83ee113eSDavid van Moolenbroek 			}
1934*83ee113eSDavid van Moolenbroek 
1935*83ee113eSDavid van Moolenbroek 			/*
1936*83ee113eSDavid van Moolenbroek 			 * We weren't able to process the request tag the
1937*83ee113eSDavid van Moolenbroek 			 * add so we won't execute it.
1938*83ee113eSDavid van Moolenbroek 			 */
1939*83ee113eSDavid van Moolenbroek 			execute_add = ISC_R_FAILURE;
1940*83ee113eSDavid van Moolenbroek 			goto cleanup;
1941*83ee113eSDavid van Moolenbroek 		}
1942*83ee113eSDavid van Moolenbroek 		else {
1943*83ee113eSDavid van Moolenbroek 			/*remove info from scope */
1944*83ee113eSDavid van Moolenbroek 			unset(*scope, "ddns-fwd-name");
1945*83ee113eSDavid van Moolenbroek 			unset(*scope, ddns_cb->lease_tag);
1946*83ee113eSDavid van Moolenbroek 		}
1947*83ee113eSDavid van Moolenbroek 	}
1948*83ee113eSDavid van Moolenbroek 
1949*83ee113eSDavid van Moolenbroek 	if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1950*83ee113eSDavid van Moolenbroek 		ddns_cb->state      = DDNS_STATE_REM_PTR;
1951*83ee113eSDavid van Moolenbroek 		ddns_cb->cur_func   = ddns_ptr_remove;
1952*83ee113eSDavid van Moolenbroek 
1953*83ee113eSDavid van Moolenbroek 		/*
1954*83ee113eSDavid van Moolenbroek 		 * if execute add isn't success remove the control block so
1955*83ee113eSDavid van Moolenbroek 		 * it won't be processed when the remove completes.  We
1956*83ee113eSDavid van Moolenbroek 		 * also arrange to clean it up and get rid of it.
1957*83ee113eSDavid van Moolenbroek 		 */
1958*83ee113eSDavid van Moolenbroek 		if (execute_add != ISC_R_SUCCESS) {
1959*83ee113eSDavid van Moolenbroek 		   	ddns_cb->next_op = NULL;
1960*83ee113eSDavid van Moolenbroek 			ddns_fwd_srv_connector(lease, lease6, scope,
1961*83ee113eSDavid van Moolenbroek 					       add_ddns_cb, execute_add);
1962*83ee113eSDavid van Moolenbroek 			add_ddns_cb = NULL;
1963*83ee113eSDavid van Moolenbroek 		}
1964*83ee113eSDavid van Moolenbroek 		else {
1965*83ee113eSDavid van Moolenbroek 			result = ISC_R_SUCCESS;
1966*83ee113eSDavid van Moolenbroek 		}
1967*83ee113eSDavid van Moolenbroek 
1968*83ee113eSDavid van Moolenbroek 		rcode = ddns_modify_ptr(ddns_cb, MDL);
1969*83ee113eSDavid van Moolenbroek 		if (rcode == ISC_R_SUCCESS) {
1970*83ee113eSDavid van Moolenbroek 			ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb,
1971*83ee113eSDavid van Moolenbroek 					      MDL);
1972*83ee113eSDavid van Moolenbroek 			return (result);
1973*83ee113eSDavid van Moolenbroek 		}
1974*83ee113eSDavid van Moolenbroek 
1975*83ee113eSDavid van Moolenbroek 		/* We weren't able to process the request tag the
1976*83ee113eSDavid van Moolenbroek 		 * add so we won't execute it */
1977*83ee113eSDavid van Moolenbroek 		execute_add = ISC_R_FAILURE;
1978*83ee113eSDavid van Moolenbroek 		goto cleanup;
1979*83ee113eSDavid van Moolenbroek 	}
1980*83ee113eSDavid van Moolenbroek 
1981*83ee113eSDavid van Moolenbroek  cleanup:
1982*83ee113eSDavid van Moolenbroek 	/*
1983*83ee113eSDavid van Moolenbroek 	 * We've gotten here because we didn't need to send a message or
1984*83ee113eSDavid van Moolenbroek 	 * we failed when trying to do so.  We send the additional cb
1985*83ee113eSDavid van Moolenbroek 	 * off to handle sending and/or cleanup and cleanup anything
1986*83ee113eSDavid van Moolenbroek 	 * we allocated here.
1987*83ee113eSDavid van Moolenbroek 	 */
1988*83ee113eSDavid van Moolenbroek 	ddns_fwd_srv_connector(lease, lease6, scope, add_ddns_cb, execute_add);
1989*83ee113eSDavid van Moolenbroek 	if (ddns_cb != NULL)
1990*83ee113eSDavid van Moolenbroek 		ddns_cb_free(ddns_cb, MDL);
1991*83ee113eSDavid van Moolenbroek 
1992*83ee113eSDavid van Moolenbroek 	return (result);
1993*83ee113eSDavid van Moolenbroek }
1994*83ee113eSDavid van Moolenbroek 
1995*83ee113eSDavid van Moolenbroek #endif /* NSUPDATE */
1996