xref: /minix3/external/bsd/dhcp/dist/common/dns.c (revision 83ee113ee0d94f3844d44065af2311604e9a30ad)
1*83ee113eSDavid van Moolenbroek /*	$NetBSD: dns.c,v 1.5 2014/07/12 12:09:37 spz Exp $	*/
2*83ee113eSDavid van Moolenbroek /* dns.c
3*83ee113eSDavid van Moolenbroek 
4*83ee113eSDavid van Moolenbroek    Domain Name Service subroutines. */
5*83ee113eSDavid van Moolenbroek 
6*83ee113eSDavid van Moolenbroek /*
7*83ee113eSDavid van Moolenbroek  * Copyright (c) 2009-2014 by Internet Systems Consortium, Inc. ("ISC")
8*83ee113eSDavid van Moolenbroek  * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
9*83ee113eSDavid van Moolenbroek  * Copyright (c) 2001-2003 by Internet Software Consortium
10*83ee113eSDavid van Moolenbroek  *
11*83ee113eSDavid van Moolenbroek  * Permission to use, copy, modify, and distribute this software for any
12*83ee113eSDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
13*83ee113eSDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
14*83ee113eSDavid van Moolenbroek  *
15*83ee113eSDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16*83ee113eSDavid van Moolenbroek  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17*83ee113eSDavid van Moolenbroek  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
18*83ee113eSDavid van Moolenbroek  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19*83ee113eSDavid van Moolenbroek  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20*83ee113eSDavid van Moolenbroek  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21*83ee113eSDavid van Moolenbroek  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22*83ee113eSDavid van Moolenbroek  *
23*83ee113eSDavid van Moolenbroek  *   Internet Systems Consortium, Inc.
24*83ee113eSDavid van Moolenbroek  *   950 Charter Street
25*83ee113eSDavid van Moolenbroek  *   Redwood City, CA 94063
26*83ee113eSDavid van Moolenbroek  *   <info@isc.org>
27*83ee113eSDavid van Moolenbroek  *   https://www.isc.org/
28*83ee113eSDavid van Moolenbroek  *
29*83ee113eSDavid van Moolenbroek  */
30*83ee113eSDavid van Moolenbroek 
31*83ee113eSDavid van Moolenbroek #include <sys/cdefs.h>
32*83ee113eSDavid van Moolenbroek __RCSID("$NetBSD: dns.c,v 1.5 2014/07/12 12:09:37 spz Exp $");
33*83ee113eSDavid van Moolenbroek 
34*83ee113eSDavid van Moolenbroek /*! \file common/dns.c
35*83ee113eSDavid van Moolenbroek  */
36*83ee113eSDavid van Moolenbroek #include "dhcpd.h"
37*83ee113eSDavid van Moolenbroek #include "arpa/nameser.h"
38*83ee113eSDavid van Moolenbroek #include <isc/md5.h>
39*83ee113eSDavid van Moolenbroek #include <isc/sha2.h>
40*83ee113eSDavid van Moolenbroek #include <dns/result.h>
41*83ee113eSDavid van Moolenbroek 
42*83ee113eSDavid van Moolenbroek /*
43*83ee113eSDavid van Moolenbroek  * This file contains code to connect the DHCP code to the libdns modules.
44*83ee113eSDavid van Moolenbroek  * As part of that function it maintains a database of zone cuts that can
45*83ee113eSDavid van Moolenbroek  * be used to figure out which server should be contacted to update any
46*83ee113eSDavid van Moolenbroek  * given domain name.  Included in the zone information may be a pointer
47*83ee113eSDavid van Moolenbroek  * to a key in which case that key is used for the update.  If no zone
48*83ee113eSDavid van Moolenbroek  * is found then the DNS code determines the zone on its own.
49*83ee113eSDavid van Moolenbroek  *
50*83ee113eSDavid van Moolenbroek  * The way this works is that you define the domain name to which an
51*83ee113eSDavid van Moolenbroek  * SOA corresponds, and the addresses of some primaries for that domain name:
52*83ee113eSDavid van Moolenbroek  *
53*83ee113eSDavid van Moolenbroek  *	zone FOO.COM {
54*83ee113eSDavid van Moolenbroek  *	  primary 10.0.17.1;
55*83ee113eSDavid van Moolenbroek  *	  secondary 10.0.22.1, 10.0.23.1;
56*83ee113eSDavid van Moolenbroek  *	  key "FOO.COM Key";
57*83ee113eSDavid van Moolenbroek  * 	}
58*83ee113eSDavid van Moolenbroek  *
59*83ee113eSDavid van Moolenbroek  * If an update is requested for GAZANGA.TOPANGA.FOO.COM, then the name
60*83ee113eSDavid van Moolenbroek  * server looks in its database for a zone record for "GAZANGA.TOPANGA.FOO.COM",
61*83ee113eSDavid van Moolenbroek  * doesn't find it, looks for one for "TOPANGA.FOO.COM", doesn't find *that*,
62*83ee113eSDavid van Moolenbroek  * looks for "FOO.COM", finds it. So it
63*83ee113eSDavid van Moolenbroek  * attempts the update to the primary for FOO.COM.   If that times out, it
64*83ee113eSDavid van Moolenbroek  * tries the secondaries.   You can list multiple primaries if you have some
65*83ee113eSDavid van Moolenbroek  * kind of magic name server that supports that.   You shouldn't list
66*83ee113eSDavid van Moolenbroek  * secondaries that don't know how to forward updates (e.g., BIND 8 doesn't
67*83ee113eSDavid van Moolenbroek  * support update forwarding, AFAIK).   If no TSIG key is listed, the update
68*83ee113eSDavid van Moolenbroek  * is attempted without TSIG.
69*83ee113eSDavid van Moolenbroek  *
70*83ee113eSDavid van Moolenbroek  * You can also include IPv6 addresses via the primary6 and secondary6
71*83ee113eSDavid van Moolenbroek  * options.  The search order for the addresses is primary, primary6,
72*83ee113eSDavid van Moolenbroek  * secondary and lastly secondary6, with a limit on the number of
73*83ee113eSDavid van Moolenbroek  * addresses used.  Currently this limit is 3.
74*83ee113eSDavid van Moolenbroek  *
75*83ee113eSDavid van Moolenbroek  * The DHCP server tries to find an existing zone for any given name by
76*83ee113eSDavid van Moolenbroek  * trying to look up a local zone structure for each domain containing
77*83ee113eSDavid van Moolenbroek  * that name, all the way up to '.'.   If it finds one cached, it tries
78*83ee113eSDavid van Moolenbroek  * to use that one to do the update.   That's why it tries to update
79*83ee113eSDavid van Moolenbroek  * "FOO.COM" above, even though theoretically it should try GAZANGA...
80*83ee113eSDavid van Moolenbroek  * and TOPANGA... first.
81*83ee113eSDavid van Moolenbroek  *
82*83ee113eSDavid van Moolenbroek  * If the update fails with a predefined zone the zone is marked as bad
83*83ee113eSDavid van Moolenbroek  * and another search of the predefined zones is done.  If no predefined
84*83ee113eSDavid van Moolenbroek  * zone is found finding a zone is left to the DNS module via examination
85*83ee113eSDavid van Moolenbroek  * of SOA records.  If the DNS module finds a zone it may cache the zone
86*83ee113eSDavid van Moolenbroek  * but the zone won't be cached here.
87*83ee113eSDavid van Moolenbroek  *
88*83ee113eSDavid van Moolenbroek  * TSIG updates are not performed on zones found by the DNS module - if
89*83ee113eSDavid van Moolenbroek  * you want TSIG updates you _must_ write a zone definition linking the
90*83ee113eSDavid van Moolenbroek  * key to the zone.   In cases where you know for sure what the key is
91*83ee113eSDavid van Moolenbroek  * but do not want to hardcode the IP addresses of the primary or
92*83ee113eSDavid van Moolenbroek  * secondaries, a zone declaration can be made that doesn't include any
93*83ee113eSDavid van Moolenbroek  * primary or secondary declarations.   When the DHCP server encounters
94*83ee113eSDavid van Moolenbroek  * this while hunting up a matching zone for a name, it looks up the SOA,
95*83ee113eSDavid van Moolenbroek  * fills in the IP addresses, and uses that record for the update.
96*83ee113eSDavid van Moolenbroek  * If the SOA lookup returns NXRRSET, a warning is printed and the zone is
97*83ee113eSDavid van Moolenbroek  * discarded, TSIG key and all.   The search for the zone then continues
98*83ee113eSDavid van Moolenbroek  * as if the zone record hadn't been found.   Zones without IP addresses
99*83ee113eSDavid van Moolenbroek  * don't match when initially hunting for a zone to update.
100*83ee113eSDavid van Moolenbroek  *
101*83ee113eSDavid van Moolenbroek  * When an update is attempted and no predefined zone is found
102*83ee113eSDavid van Moolenbroek  * that matches any enclosing domain of the domain being updated, the DHCP
103*83ee113eSDavid van Moolenbroek  * server goes through the same process that is done when the update to a
104*83ee113eSDavid van Moolenbroek  * predefined zone fails - starting with the most specific domain
105*83ee113eSDavid van Moolenbroek  * name (GAZANGA.TOPANGA.FOO.COM) and moving to the least specific (the root),
106*83ee113eSDavid van Moolenbroek  * it tries to look up an SOA record.
107*83ee113eSDavid van Moolenbroek  *
108*83ee113eSDavid van Moolenbroek  * TSIG keys are defined like this:
109*83ee113eSDavid van Moolenbroek  *
110*83ee113eSDavid van Moolenbroek  *	key "FOO.COM Key" {
111*83ee113eSDavid van Moolenbroek  *		algorithm HMAC-MD5.SIG-ALG.REG.INT;
112*83ee113eSDavid van Moolenbroek  *		secret <Base64>;
113*83ee113eSDavid van Moolenbroek  *	}
114*83ee113eSDavid van Moolenbroek  *
115*83ee113eSDavid van Moolenbroek  * <Base64> is a number expressed in base64 that represents the key.
116*83ee113eSDavid van Moolenbroek  * It's also permissible to use a quoted string here - this will be
117*83ee113eSDavid van Moolenbroek  * translated as the ASCII bytes making up the string, and will not
118*83ee113eSDavid van Moolenbroek  * include any NUL termination.  The key name can be any text string,
119*83ee113eSDavid van Moolenbroek  * and the key type must be one of the key types defined in the draft
120*83ee113eSDavid van Moolenbroek  * or by the IANA.  Currently only the HMAC-MD5... key type is
121*83ee113eSDavid van Moolenbroek  * supported.
122*83ee113eSDavid van Moolenbroek  *
123*83ee113eSDavid van Moolenbroek  * The DDNS processing has been split into two areas.  One is the
124*83ee113eSDavid van Moolenbroek  * control code that determines what should be done.  That code is found
125*83ee113eSDavid van Moolenbroek  * in the client or server directories.  The other is the common code
126*83ee113eSDavid van Moolenbroek  * that performs functions such as properly formatting the arguments.
127*83ee113eSDavid van Moolenbroek  * That code is found in this file.  The basic processing flow for a
128*83ee113eSDavid van Moolenbroek  * DDNS update is:
129*83ee113eSDavid van Moolenbroek  * In the client or server code determine what needs to be done and
130*83ee113eSDavid van Moolenbroek  * collect the necesary information then pass it to a function from
131*83ee113eSDavid van Moolenbroek  * this file.
132*83ee113eSDavid van Moolenbroek  * In this code lookup the zone and extract the zone and key information
133*83ee113eSDavid van Moolenbroek  * (if available) and prepare the arguments for the DNS module.
134*83ee113eSDavid van Moolenbroek  * When the DNS module completes its work (times out or gets a reply)
135*83ee113eSDavid van Moolenbroek  * it will trigger another function here which does generic processing
136*83ee113eSDavid van Moolenbroek  * and then passes control back to the code from the server or client.
137*83ee113eSDavid van Moolenbroek  * The server or client code then determines the next step which may
138*83ee113eSDavid van Moolenbroek  * result in another call to this module in which case the process repeats.
139*83ee113eSDavid van Moolenbroek  */
140*83ee113eSDavid van Moolenbroek 
141*83ee113eSDavid van Moolenbroek dns_zone_hash_t *dns_zone_hash;
142*83ee113eSDavid van Moolenbroek 
143*83ee113eSDavid van Moolenbroek /*
144*83ee113eSDavid van Moolenbroek  * DHCP dns structures
145*83ee113eSDavid van Moolenbroek  * Normally the relationship between these structures isn't one to one
146*83ee113eSDavid van Moolenbroek  * but in the DHCP case it (mostly) is.  To make the allocations, frees,
147*83ee113eSDavid van Moolenbroek  * and passing of the memory easier we make a single structure with all
148*83ee113eSDavid van Moolenbroek  * the pieces.
149*83ee113eSDavid van Moolenbroek  *
150*83ee113eSDavid van Moolenbroek  * The maximum size of the data buffer should be large enough for any
151*83ee113eSDavid van Moolenbroek  * items DHCP will generate
152*83ee113eSDavid van Moolenbroek  */
153*83ee113eSDavid van Moolenbroek 
154*83ee113eSDavid van Moolenbroek typedef struct dhcp_ddns_rdata {
155*83ee113eSDavid van Moolenbroek 	dns_rdata_t	rdata;
156*83ee113eSDavid van Moolenbroek 	dns_rdatalist_t rdatalist;
157*83ee113eSDavid van Moolenbroek 	dns_rdataset_t  rdataset;
158*83ee113eSDavid van Moolenbroek } dhcp_ddns_data_t;
159*83ee113eSDavid van Moolenbroek 
160*83ee113eSDavid van Moolenbroek #if defined (NSUPDATE)
161*83ee113eSDavid van Moolenbroek #if defined (DNS_ZONE_LOOKUP)
162*83ee113eSDavid van Moolenbroek 
163*83ee113eSDavid van Moolenbroek /*
164*83ee113eSDavid van Moolenbroek  * The structure used to find a nameserver if there wasn't a zone entry.
165*83ee113eSDavid van Moolenbroek  * Currently we assume we won't have many of these outstanding at any
166*83ee113eSDavid van Moolenbroek  * time so we go with a simple linked list.
167*83ee113eSDavid van Moolenbroek  * In use find_zone_start() will fill in the oname with the name
168*83ee113eSDavid van Moolenbroek  * requested by the DDNS code.  zname will point to it and be
169*83ee113eSDavid van Moolenbroek  * advanced as labels are removed.  If the DNS client code returns
170*83ee113eSDavid van Moolenbroek  * a set of name servers eventp and rdataset will be set.  Then
171*83ee113eSDavid van Moolenbroek  * the code will walk through the nameservers in namelist and
172*83ee113eSDavid van Moolenbroek  * find addresses that are stored in addrs and addrs6.
173*83ee113eSDavid van Moolenbroek  */
174*83ee113eSDavid van Moolenbroek 
175*83ee113eSDavid van Moolenbroek typedef struct dhcp_ddns_ns {
176*83ee113eSDavid van Moolenbroek 	struct dhcp_ddns_ns *next;
177*83ee113eSDavid van Moolenbroek 	struct data_string oname;     /* the original name for DDNS */
178*83ee113eSDavid van Moolenbroek 	char *zname;                  /* a pointer into the original name for
179*83ee113eSDavid van Moolenbroek 					 the zone we are checking */
180*83ee113eSDavid van Moolenbroek 	dns_clientresevent_t *eventp; /* pointer to the event that provided the
181*83ee113eSDavid van Moolenbroek 					 namelist, we can't free the eventp
182*83ee113eSDavid van Moolenbroek 					 until we free the namelist */
183*83ee113eSDavid van Moolenbroek 	dns_name_t *ns_name;          /* current name server we are examining */
184*83ee113eSDavid van Moolenbroek 	dns_rdataset_t *rdataset;
185*83ee113eSDavid van Moolenbroek 	dns_rdatatype_t rdtype;       /* type of address we want */
186*83ee113eSDavid van Moolenbroek 
187*83ee113eSDavid van Moolenbroek 	struct in_addr addrs[DHCP_MAXNS];   /* space for v4 addresses */
188*83ee113eSDavid van Moolenbroek 	struct in6_addr addrs6[DHCP_MAXNS]; /* space for v6 addresses */
189*83ee113eSDavid van Moolenbroek 	int num_addrs;
190*83ee113eSDavid van Moolenbroek 	int num_addrs6;
191*83ee113eSDavid van Moolenbroek 	int ttl;
192*83ee113eSDavid van Moolenbroek 
193*83ee113eSDavid van Moolenbroek 	void *transaction;             /* transaction id for DNS calls */
194*83ee113eSDavid van Moolenbroek } dhcp_ddns_ns_t;
195*83ee113eSDavid van Moolenbroek 
196*83ee113eSDavid van Moolenbroek /*
197*83ee113eSDavid van Moolenbroek  * The list of DDNS names for which we are attempting to find a name server.
198*83ee113eSDavid van Moolenbroek  * This list is used for finding the name server, it doesn't include the
199*83ee113eSDavid van Moolenbroek  * information necessary to do the DDNS request after finding a name server.
200*83ee113eSDavid van Moolenbroek  * The code attempts to minimize duplicate requests by examining the list
201*83ee113eSDavid van Moolenbroek  * to see if we are already trying to find a substring of the new request.
202*83ee113eSDavid van Moolenbroek  * For example imagine the first request is "a.b.c.d.e." and the server has
203*83ee113eSDavid van Moolenbroek  * already discarded the first two lables and is trying "c.d.e.".  If the
204*83ee113eSDavid van Moolenbroek  * next request is for "x.y.c.d.e." the code assumes the in progress
205*83ee113eSDavid van Moolenbroek  * request is sufficient and doesn't add a new request for the second name.
206*83ee113eSDavid van Moolenbroek  * If the next request was for "x.y.z.d.e." the code doesn't assume they
207*83ee113eSDavid van Moolenbroek  * will use the same nameserver and starts a second request.
208*83ee113eSDavid van Moolenbroek  * This strategy will not eliminate all duplicates but is simple and
209*83ee113eSDavid van Moolenbroek  * should be sufficient.
210*83ee113eSDavid van Moolenbroek  */
211*83ee113eSDavid van Moolenbroek dhcp_ddns_ns_t *dns_outstanding_ns = NULL;
212*83ee113eSDavid van Moolenbroek 
213*83ee113eSDavid van Moolenbroek /*
214*83ee113eSDavid van Moolenbroek  * Routines to manipulate the list of outstanding searches
215*83ee113eSDavid van Moolenbroek  *
216*83ee113eSDavid van Moolenbroek  * add_to_ns_queue() - adds the given control block to the queue
217*83ee113eSDavid van Moolenbroek  *
218*83ee113eSDavid van Moolenbroek  * remove_from_ns_queue() - removes the given control block from
219*83ee113eSDavid van Moolenbroek  * the queue
220*83ee113eSDavid van Moolenbroek  *
221*83ee113eSDavid van Moolenbroek  * find_in_ns_queue() compares the name from the given control
222*83ee113eSDavid van Moolenbroek  * block with the control blocks in the queue.  It returns
223*83ee113eSDavid van Moolenbroek  * success if a matching entry is found.  In order to match
224*83ee113eSDavid van Moolenbroek  * the entry already on the queue must be shorter than the
225*83ee113eSDavid van Moolenbroek  * incoming name must match the ending substring of the name.
226*83ee113eSDavid van Moolenbroek  */
227*83ee113eSDavid van Moolenbroek 
228*83ee113eSDavid van Moolenbroek static void
add_to_ns_queue(dhcp_ddns_ns_t * ns_cb)229*83ee113eSDavid van Moolenbroek add_to_ns_queue(dhcp_ddns_ns_t *ns_cb)
230*83ee113eSDavid van Moolenbroek {
231*83ee113eSDavid van Moolenbroek 	ns_cb->next = dns_outstanding_ns;
232*83ee113eSDavid van Moolenbroek 	dns_outstanding_ns = ns_cb;
233*83ee113eSDavid van Moolenbroek }
234*83ee113eSDavid van Moolenbroek 
235*83ee113eSDavid van Moolenbroek 
236*83ee113eSDavid van Moolenbroek static void
remove_from_ns_queue(dhcp_ddns_ns_t * ns_cb)237*83ee113eSDavid van Moolenbroek remove_from_ns_queue(dhcp_ddns_ns_t *ns_cb)
238*83ee113eSDavid van Moolenbroek {
239*83ee113eSDavid van Moolenbroek 	dhcp_ddns_ns_t **foo;
240*83ee113eSDavid van Moolenbroek 
241*83ee113eSDavid van Moolenbroek 	foo = &dns_outstanding_ns;
242*83ee113eSDavid van Moolenbroek 	while (*foo) {
243*83ee113eSDavid van Moolenbroek 		if (*foo == ns_cb) {
244*83ee113eSDavid van Moolenbroek 			*foo = ns_cb->next;
245*83ee113eSDavid van Moolenbroek 			break;
246*83ee113eSDavid van Moolenbroek 		}
247*83ee113eSDavid van Moolenbroek 		foo = &((*foo)->next);
248*83ee113eSDavid van Moolenbroek 	}
249*83ee113eSDavid van Moolenbroek 	ns_cb->next = NULL;
250*83ee113eSDavid van Moolenbroek }
251*83ee113eSDavid van Moolenbroek 
252*83ee113eSDavid van Moolenbroek static isc_result_t
find_in_ns_queue(dhcp_ddns_ns_t * ns_cb)253*83ee113eSDavid van Moolenbroek find_in_ns_queue(dhcp_ddns_ns_t *ns_cb)
254*83ee113eSDavid van Moolenbroek {
255*83ee113eSDavid van Moolenbroek 	dhcp_ddns_ns_t *temp_cb;
256*83ee113eSDavid van Moolenbroek 	int in_len, temp_len;
257*83ee113eSDavid van Moolenbroek 
258*83ee113eSDavid van Moolenbroek 	in_len = strlen(ns_cb->zname);
259*83ee113eSDavid van Moolenbroek 
260*83ee113eSDavid van Moolenbroek 	for(temp_cb = dns_outstanding_ns;
261*83ee113eSDavid van Moolenbroek 	    temp_cb != NULL;
262*83ee113eSDavid van Moolenbroek 	    temp_cb = temp_cb->next) {
263*83ee113eSDavid van Moolenbroek 		temp_len = strlen(temp_cb->zname);
264*83ee113eSDavid van Moolenbroek 		if (temp_len > in_len)
265*83ee113eSDavid van Moolenbroek 			continue;
266*83ee113eSDavid van Moolenbroek 		if (strcmp(temp_cb->zname,
267*83ee113eSDavid van Moolenbroek 			   ns_cb->zname + (in_len - temp_len)) == 0)
268*83ee113eSDavid van Moolenbroek 			return(ISC_R_SUCCESS);
269*83ee113eSDavid van Moolenbroek 	}
270*83ee113eSDavid van Moolenbroek 	return(ISC_R_NOTFOUND);
271*83ee113eSDavid van Moolenbroek }
272*83ee113eSDavid van Moolenbroek 
273*83ee113eSDavid van Moolenbroek void cache_found_zone (dhcp_ddns_ns_t *);
274*83ee113eSDavid van Moolenbroek #endif
275*83ee113eSDavid van Moolenbroek 
276*83ee113eSDavid van Moolenbroek void ddns_interlude(isc_task_t *, isc_event_t *);
277*83ee113eSDavid van Moolenbroek 
278*83ee113eSDavid van Moolenbroek #if defined (TRACING)
279*83ee113eSDavid van Moolenbroek /*
280*83ee113eSDavid van Moolenbroek  * Code to support tracing DDNS packets.  We trace packets going to and
281*83ee113eSDavid van Moolenbroek  * coming from the libdns code but don't try to track the packets
282*83ee113eSDavid van Moolenbroek  * exchanged between the libdns code and the dns server(s) it contacts.
283*83ee113eSDavid van Moolenbroek  *
284*83ee113eSDavid van Moolenbroek  * The code is split into two sets of routines
285*83ee113eSDavid van Moolenbroek  *  input refers to messages received from the dns module
286*83ee113eSDavid van Moolenbroek  *  output refers to messages sent to the dns module
287*83ee113eSDavid van Moolenbroek  * Currently there are three routines in each set
288*83ee113eSDavid van Moolenbroek  *  write is used to write information about the message to the trace file
289*83ee113eSDavid van Moolenbroek  *        this routine is called directly from the proper place in the code.
290*83ee113eSDavid van Moolenbroek  *  read is used to read information about a message from the trace file
291*83ee113eSDavid van Moolenbroek  *       this routine is called from the trace loop as it reads through
292*83ee113eSDavid van Moolenbroek  *       the file and is registered via the trace_type_register routine.
293*83ee113eSDavid van Moolenbroek  *       When playing back a trace file we shall absorb records of output
294*83ee113eSDavid van Moolenbroek  *       messages as part of processing the write function, therefore
295*83ee113eSDavid van Moolenbroek  *       any output messages we encounter are flagged as errors.
296*83ee113eSDavid van Moolenbroek  *  stop isn't currently used in this code but is needed for the register
297*83ee113eSDavid van Moolenbroek  *       routine.
298*83ee113eSDavid van Moolenbroek  *
299*83ee113eSDavid van Moolenbroek  * We pass a pointer to a control block to the dns module which it returns
300*83ee113eSDavid van Moolenbroek  * to use as part of the result.  As the pointer may vary between traces
301*83ee113eSDavid van Moolenbroek  * we need to map between those from the trace file and the new ones during
302*83ee113eSDavid van Moolenbroek  * playback.
303*83ee113eSDavid van Moolenbroek  *
304*83ee113eSDavid van Moolenbroek  * The mapping is complicated a little as a pointer could be 4 or 8 bytes
305*83ee113eSDavid van Moolenbroek  * long.  We treat the old pointer as an 8 byte quantity and pad and compare
306*83ee113eSDavid van Moolenbroek  * as necessary.
307*83ee113eSDavid van Moolenbroek  */
308*83ee113eSDavid van Moolenbroek 
309*83ee113eSDavid van Moolenbroek /*
310*83ee113eSDavid van Moolenbroek  * Structure used to map old pointers to new pointers.
311*83ee113eSDavid van Moolenbroek  * Old pointers are 8 bytes long as we don't know if the trace was
312*83ee113eSDavid van Moolenbroek  * done on a 64 bit or 32 bit machine.
313*83ee113eSDavid van Moolenbroek  */
314*83ee113eSDavid van Moolenbroek #define TRACE_PTR_LEN 8
315*83ee113eSDavid van Moolenbroek 
316*83ee113eSDavid van Moolenbroek typedef struct dhcp_ddns_map {
317*83ee113eSDavid van Moolenbroek 	char  old_pointer[TRACE_PTR_LEN];
318*83ee113eSDavid van Moolenbroek 	void *new_pointer;
319*83ee113eSDavid van Moolenbroek 	struct dhcp_ddns_map *next;
320*83ee113eSDavid van Moolenbroek } dhcp_ddns_map_t;
321*83ee113eSDavid van Moolenbroek 
322*83ee113eSDavid van Moolenbroek /* The starting point for the map structure */
323*83ee113eSDavid van Moolenbroek static dhcp_ddns_map_t *ddns_map;
324*83ee113eSDavid van Moolenbroek 
325*83ee113eSDavid van Moolenbroek trace_type_t *trace_ddns_input;
326*83ee113eSDavid van Moolenbroek trace_type_t *trace_ddns_output;
327*83ee113eSDavid van Moolenbroek 
328*83ee113eSDavid van Moolenbroek /*
329*83ee113eSDavid van Moolenbroek  * The data written to the trace file is:
330*83ee113eSDavid van Moolenbroek  * 32 bits result from dns
331*83ee113eSDavid van Moolenbroek  * 64 bits pointer of cb
332*83ee113eSDavid van Moolenbroek  */
333*83ee113eSDavid van Moolenbroek 
334*83ee113eSDavid van Moolenbroek static void
trace_ddns_input_write(dhcp_ddns_cb_t * ddns_cb,isc_result_t result)335*83ee113eSDavid van Moolenbroek trace_ddns_input_write(dhcp_ddns_cb_t *ddns_cb, isc_result_t result)
336*83ee113eSDavid van Moolenbroek {
337*83ee113eSDavid van Moolenbroek 	trace_iov_t iov[2];
338*83ee113eSDavid van Moolenbroek 	u_int32_t old_result;
339*83ee113eSDavid van Moolenbroek 	char old_pointer[TRACE_PTR_LEN];
340*83ee113eSDavid van Moolenbroek 
341*83ee113eSDavid van Moolenbroek 	old_result = htonl((u_int32_t)result);
342*83ee113eSDavid van Moolenbroek 	memset(old_pointer, 0, TRACE_PTR_LEN);
343*83ee113eSDavid van Moolenbroek 	memcpy(old_pointer, &ddns_cb, sizeof(ddns_cb));
344*83ee113eSDavid van Moolenbroek 
345*83ee113eSDavid van Moolenbroek 	iov[0].len = sizeof(old_result);
346*83ee113eSDavid van Moolenbroek 	iov[0].buf = (char *)&old_result;
347*83ee113eSDavid van Moolenbroek 	iov[1].len = TRACE_PTR_LEN;
348*83ee113eSDavid van Moolenbroek 	iov[1].buf = old_pointer;
349*83ee113eSDavid van Moolenbroek 	trace_write_packet_iov(trace_ddns_input, 2, iov, MDL);
350*83ee113eSDavid van Moolenbroek }
351*83ee113eSDavid van Moolenbroek 
352*83ee113eSDavid van Moolenbroek /*
353*83ee113eSDavid van Moolenbroek  * Process the result and pointer from the trace file.
354*83ee113eSDavid van Moolenbroek  * We use the pointer map to find the proper pointer for this instance.
355*83ee113eSDavid van Moolenbroek  * Then we need to construct an event to pass along to the interlude
356*83ee113eSDavid van Moolenbroek  * function.
357*83ee113eSDavid van Moolenbroek  */
358*83ee113eSDavid van Moolenbroek static void
trace_ddns_input_read(trace_type_t * ttype,unsigned length,char * buf)359*83ee113eSDavid van Moolenbroek trace_ddns_input_read(trace_type_t *ttype, unsigned length,
360*83ee113eSDavid van Moolenbroek 				  char *buf)
361*83ee113eSDavid van Moolenbroek {
362*83ee113eSDavid van Moolenbroek 	u_int32_t old_result;
363*83ee113eSDavid van Moolenbroek 	char old_pointer[TRACE_PTR_LEN];
364*83ee113eSDavid van Moolenbroek 	dns_clientupdateevent_t *eventp;
365*83ee113eSDavid van Moolenbroek 	void *new_pointer;
366*83ee113eSDavid van Moolenbroek 	dhcp_ddns_map_t *ddns_map_ptr;
367*83ee113eSDavid van Moolenbroek 
368*83ee113eSDavid van Moolenbroek 	if (length < (sizeof(old_result) + TRACE_PTR_LEN)) {
369*83ee113eSDavid van Moolenbroek 		log_error("trace_ddns_input_read: data too short");
370*83ee113eSDavid van Moolenbroek 		return;
371*83ee113eSDavid van Moolenbroek 	}
372*83ee113eSDavid van Moolenbroek 
373*83ee113eSDavid van Moolenbroek 	memcpy(&old_result, buf, sizeof(old_result));
374*83ee113eSDavid van Moolenbroek 	memcpy(old_pointer, buf + sizeof(old_result), TRACE_PTR_LEN);
375*83ee113eSDavid van Moolenbroek 
376*83ee113eSDavid van Moolenbroek 	/* map the old pointer to a new pointer */
377*83ee113eSDavid van Moolenbroek 	for (ddns_map_ptr = ddns_map;
378*83ee113eSDavid van Moolenbroek 	     ddns_map_ptr != NULL;
379*83ee113eSDavid van Moolenbroek 	     ddns_map_ptr = ddns_map_ptr->next) {
380*83ee113eSDavid van Moolenbroek 		if ((ddns_map_ptr->new_pointer != NULL) &&
381*83ee113eSDavid van Moolenbroek 		    memcmp(ddns_map_ptr->old_pointer,
382*83ee113eSDavid van Moolenbroek 			   old_pointer, TRACE_PTR_LEN) == 0) {
383*83ee113eSDavid van Moolenbroek 			new_pointer = ddns_map_ptr->new_pointer;
384*83ee113eSDavid van Moolenbroek 			ddns_map_ptr->new_pointer = NULL;
385*83ee113eSDavid van Moolenbroek 			memset(ddns_map_ptr->old_pointer, 0, TRACE_PTR_LEN);
386*83ee113eSDavid van Moolenbroek 			break;
387*83ee113eSDavid van Moolenbroek 		}
388*83ee113eSDavid van Moolenbroek 	}
389*83ee113eSDavid van Moolenbroek 	if (ddns_map_ptr == NULL) {
390*83ee113eSDavid van Moolenbroek 		log_error("trace_dns_input_read: unable to map cb pointer");
391*83ee113eSDavid van Moolenbroek 		return;
392*83ee113eSDavid van Moolenbroek 	}
393*83ee113eSDavid van Moolenbroek 
394*83ee113eSDavid van Moolenbroek 	eventp = (dns_clientupdateevent_t *)
395*83ee113eSDavid van Moolenbroek 		isc_event_allocate(dhcp_gbl_ctx.mctx,
396*83ee113eSDavid van Moolenbroek 				   dhcp_gbl_ctx.task,
397*83ee113eSDavid van Moolenbroek 				   0,
398*83ee113eSDavid van Moolenbroek 				   ddns_interlude,
399*83ee113eSDavid van Moolenbroek 				   new_pointer,
400*83ee113eSDavid van Moolenbroek 				   sizeof(dns_clientupdateevent_t));
401*83ee113eSDavid van Moolenbroek 	if (eventp == NULL) {
402*83ee113eSDavid van Moolenbroek 		log_error("trace_ddns_input_read: unable to allocate event");
403*83ee113eSDavid van Moolenbroek 		return;
404*83ee113eSDavid van Moolenbroek 	}
405*83ee113eSDavid van Moolenbroek 	eventp->result = ntohl(old_result);
406*83ee113eSDavid van Moolenbroek 
407*83ee113eSDavid van Moolenbroek 
408*83ee113eSDavid van Moolenbroek 	ddns_interlude(dhcp_gbl_ctx.task, (isc_event_t *)eventp);
409*83ee113eSDavid van Moolenbroek 
410*83ee113eSDavid van Moolenbroek 	return;
411*83ee113eSDavid van Moolenbroek }
412*83ee113eSDavid van Moolenbroek 
413*83ee113eSDavid van Moolenbroek static void
trace_ddns_input_stop(trace_type_t * ttype)414*83ee113eSDavid van Moolenbroek trace_ddns_input_stop(trace_type_t *ttype)
415*83ee113eSDavid van Moolenbroek {
416*83ee113eSDavid van Moolenbroek }
417*83ee113eSDavid van Moolenbroek 
418*83ee113eSDavid van Moolenbroek /*
419*83ee113eSDavid van Moolenbroek  * We use the same arguments as for the dns startupdate function to
420*83ee113eSDavid van Moolenbroek  * allows us to choose between the two via a macro.  If tracing isn't
421*83ee113eSDavid van Moolenbroek  * in use we simply call the dns function directly.
422*83ee113eSDavid van Moolenbroek  *
423*83ee113eSDavid van Moolenbroek  * If we are doing playback we read the next packet from the file
424*83ee113eSDavid van Moolenbroek  * and compare the type.  If it matches we extract the results and pointer
425*83ee113eSDavid van Moolenbroek  * from the trace file.  The results are returned to the caller as if
426*83ee113eSDavid van Moolenbroek  * they had called the dns routine.  The pointer is used to construct a
427*83ee113eSDavid van Moolenbroek  * map for when the "reply" is processed.
428*83ee113eSDavid van Moolenbroek  *
429*83ee113eSDavid van Moolenbroek  * The data written to trace file is:
430*83ee113eSDavid van Moolenbroek  * 32 bits result
431*83ee113eSDavid van Moolenbroek  * 64 bits pointer of cb (DDNS Control block)
432*83ee113eSDavid van Moolenbroek  * contents of cb
433*83ee113eSDavid van Moolenbroek  */
434*83ee113eSDavid van Moolenbroek 
435*83ee113eSDavid van Moolenbroek static isc_result_t
trace_ddns_output_write(dns_client_t * client,dns_rdataclass_t rdclass,dns_name_t * zonename,dns_namelist_t * prerequisites,dns_namelist_t * updates,isc_sockaddrlist_t * servers,dns_tsec_t * tsec,unsigned int options,isc_task_t * task,isc_taskaction_t action,void * arg,dns_clientupdatetrans_t ** transp)436*83ee113eSDavid van Moolenbroek trace_ddns_output_write(dns_client_t *client, dns_rdataclass_t rdclass,
437*83ee113eSDavid van Moolenbroek 			dns_name_t *zonename, dns_namelist_t *prerequisites,
438*83ee113eSDavid van Moolenbroek 			dns_namelist_t *updates, isc_sockaddrlist_t *servers,
439*83ee113eSDavid van Moolenbroek 			dns_tsec_t *tsec, unsigned int options,
440*83ee113eSDavid van Moolenbroek 			isc_task_t *task, isc_taskaction_t action, void *arg,
441*83ee113eSDavid van Moolenbroek 			dns_clientupdatetrans_t **transp)
442*83ee113eSDavid van Moolenbroek {
443*83ee113eSDavid van Moolenbroek 	isc_result_t result;
444*83ee113eSDavid van Moolenbroek 	u_int32_t old_result;
445*83ee113eSDavid van Moolenbroek 	char old_pointer[TRACE_PTR_LEN];
446*83ee113eSDavid van Moolenbroek 	dhcp_ddns_map_t *ddns_map_ptr;
447*83ee113eSDavid van Moolenbroek 
448*83ee113eSDavid van Moolenbroek 	if (trace_playback() != 0) {
449*83ee113eSDavid van Moolenbroek 		/* We are doing playback, extract the entry from the file */
450*83ee113eSDavid van Moolenbroek 		unsigned buflen = 0;
451*83ee113eSDavid van Moolenbroek 		char *inbuf = NULL;
452*83ee113eSDavid van Moolenbroek 
453*83ee113eSDavid van Moolenbroek 		result = trace_get_packet(&trace_ddns_output,
454*83ee113eSDavid van Moolenbroek 					  &buflen, &inbuf);
455*83ee113eSDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
456*83ee113eSDavid van Moolenbroek 			log_error("trace_ddns_output_write: no input found");
457*83ee113eSDavid van Moolenbroek 			return (ISC_R_FAILURE);
458*83ee113eSDavid van Moolenbroek 		}
459*83ee113eSDavid van Moolenbroek 		if (buflen < (sizeof(old_result) + TRACE_PTR_LEN)) {
460*83ee113eSDavid van Moolenbroek 			log_error("trace_ddns_output_write: data too short");
461*83ee113eSDavid van Moolenbroek 			dfree(inbuf, MDL);
462*83ee113eSDavid van Moolenbroek 			return (ISC_R_FAILURE);
463*83ee113eSDavid van Moolenbroek 		}
464*83ee113eSDavid van Moolenbroek 		memcpy(&old_result, inbuf, sizeof(old_result));
465*83ee113eSDavid van Moolenbroek 		result = ntohl(old_result);
466*83ee113eSDavid van Moolenbroek 		memcpy(old_pointer, inbuf + sizeof(old_result), TRACE_PTR_LEN);
467*83ee113eSDavid van Moolenbroek 		dfree(inbuf, MDL);
468*83ee113eSDavid van Moolenbroek 
469*83ee113eSDavid van Moolenbroek 		/* add the pointer to the pointer map */
470*83ee113eSDavid van Moolenbroek 		for (ddns_map_ptr = ddns_map;
471*83ee113eSDavid van Moolenbroek 		     ddns_map_ptr != NULL;
472*83ee113eSDavid van Moolenbroek 		     ddns_map_ptr = ddns_map_ptr->next) {
473*83ee113eSDavid van Moolenbroek 			if (ddns_map_ptr->new_pointer == NULL) {
474*83ee113eSDavid van Moolenbroek 				break;
475*83ee113eSDavid van Moolenbroek 			}
476*83ee113eSDavid van Moolenbroek 		}
477*83ee113eSDavid van Moolenbroek 
478*83ee113eSDavid van Moolenbroek 		/*
479*83ee113eSDavid van Moolenbroek 		 * If we didn't find an empty entry, allocate an entry and
480*83ee113eSDavid van Moolenbroek 		 * link it into the list.  The list isn't ordered.
481*83ee113eSDavid van Moolenbroek 		 */
482*83ee113eSDavid van Moolenbroek 		if (ddns_map_ptr == NULL) {
483*83ee113eSDavid van Moolenbroek 			ddns_map_ptr = dmalloc(sizeof(*ddns_map_ptr), MDL);
484*83ee113eSDavid van Moolenbroek 			if (ddns_map_ptr == NULL) {
485*83ee113eSDavid van Moolenbroek 				log_error("trace_ddns_output_write: "
486*83ee113eSDavid van Moolenbroek 					  "unable to allocate map entry");
487*83ee113eSDavid van Moolenbroek 				return(ISC_R_FAILURE);
488*83ee113eSDavid van Moolenbroek 				}
489*83ee113eSDavid van Moolenbroek 			ddns_map_ptr->next = ddns_map;
490*83ee113eSDavid van Moolenbroek 			ddns_map = ddns_map_ptr;
491*83ee113eSDavid van Moolenbroek 		}
492*83ee113eSDavid van Moolenbroek 
493*83ee113eSDavid van Moolenbroek 		memcpy(ddns_map_ptr->old_pointer, old_pointer, TRACE_PTR_LEN);
494*83ee113eSDavid van Moolenbroek 		ddns_map_ptr->new_pointer = arg;
495*83ee113eSDavid van Moolenbroek 	}
496*83ee113eSDavid van Moolenbroek 	else {
497*83ee113eSDavid van Moolenbroek 		/* We aren't doing playback, make the actual call */
498*83ee113eSDavid van Moolenbroek 		result = dns_client_startupdate(client, rdclass, zonename,
499*83ee113eSDavid van Moolenbroek 						prerequisites, updates,
500*83ee113eSDavid van Moolenbroek 						servers, tsec, options,
501*83ee113eSDavid van Moolenbroek 						task, action, arg, transp);
502*83ee113eSDavid van Moolenbroek 	}
503*83ee113eSDavid van Moolenbroek 
504*83ee113eSDavid van Moolenbroek 	if (trace_record() != 0) {
505*83ee113eSDavid van Moolenbroek 		/* We are recording, save the information to the file */
506*83ee113eSDavid van Moolenbroek 		trace_iov_t iov[3];
507*83ee113eSDavid van Moolenbroek 		old_result = htonl((u_int32_t)result);
508*83ee113eSDavid van Moolenbroek 		memset(old_pointer, 0, TRACE_PTR_LEN);
509*83ee113eSDavid van Moolenbroek 		memcpy(old_pointer, &arg, sizeof(arg));
510*83ee113eSDavid van Moolenbroek 		iov[0].len = sizeof(old_result);
511*83ee113eSDavid van Moolenbroek 		iov[0].buf = (char *)&old_result;
512*83ee113eSDavid van Moolenbroek 		iov[1].len = TRACE_PTR_LEN;
513*83ee113eSDavid van Moolenbroek 		iov[1].buf = old_pointer;
514*83ee113eSDavid van Moolenbroek 
515*83ee113eSDavid van Moolenbroek 		/* Write out the entire cb, in case we want to look at it */
516*83ee113eSDavid van Moolenbroek 		iov[2].len = sizeof(dhcp_ddns_cb_t);
517*83ee113eSDavid van Moolenbroek 		iov[2].buf = (char *)arg;
518*83ee113eSDavid van Moolenbroek 
519*83ee113eSDavid van Moolenbroek 		trace_write_packet_iov(trace_ddns_output, 3, iov, MDL);
520*83ee113eSDavid van Moolenbroek 	}
521*83ee113eSDavid van Moolenbroek 
522*83ee113eSDavid van Moolenbroek 	return(result);
523*83ee113eSDavid van Moolenbroek }
524*83ee113eSDavid van Moolenbroek 
525*83ee113eSDavid van Moolenbroek static void
trace_ddns_output_read(trace_type_t * ttype,unsigned length,char * buf)526*83ee113eSDavid van Moolenbroek trace_ddns_output_read(trace_type_t *ttype, unsigned length,
527*83ee113eSDavid van Moolenbroek 				   char *buf)
528*83ee113eSDavid van Moolenbroek {
529*83ee113eSDavid van Moolenbroek 	log_error("unaccounted for ddns output.");
530*83ee113eSDavid van Moolenbroek }
531*83ee113eSDavid van Moolenbroek 
532*83ee113eSDavid van Moolenbroek static void
trace_ddns_output_stop(trace_type_t * ttype)533*83ee113eSDavid van Moolenbroek trace_ddns_output_stop(trace_type_t *ttype)
534*83ee113eSDavid van Moolenbroek {
535*83ee113eSDavid van Moolenbroek }
536*83ee113eSDavid van Moolenbroek 
537*83ee113eSDavid van Moolenbroek void
trace_ddns_init()538*83ee113eSDavid van Moolenbroek trace_ddns_init()
539*83ee113eSDavid van Moolenbroek {
540*83ee113eSDavid van Moolenbroek 	trace_ddns_output = trace_type_register("ddns-output", NULL,
541*83ee113eSDavid van Moolenbroek 						trace_ddns_output_read,
542*83ee113eSDavid van Moolenbroek 						trace_ddns_output_stop, MDL);
543*83ee113eSDavid van Moolenbroek 	trace_ddns_input  = trace_type_register("ddns-input", NULL,
544*83ee113eSDavid van Moolenbroek 						trace_ddns_input_read,
545*83ee113eSDavid van Moolenbroek 						trace_ddns_input_stop, MDL);
546*83ee113eSDavid van Moolenbroek 	ddns_map = NULL;
547*83ee113eSDavid van Moolenbroek }
548*83ee113eSDavid van Moolenbroek 
549*83ee113eSDavid van Moolenbroek #define ddns_update trace_ddns_output_write
550*83ee113eSDavid van Moolenbroek #else
551*83ee113eSDavid van Moolenbroek #define ddns_update dns_client_startupdate
552*83ee113eSDavid van Moolenbroek #endif /* TRACING */
553*83ee113eSDavid van Moolenbroek 
554*83ee113eSDavid van Moolenbroek #define zone_resolve dns_client_startresolve
555*83ee113eSDavid van Moolenbroek 
556*83ee113eSDavid van Moolenbroek /*
557*83ee113eSDavid van Moolenbroek  * Code to allocate and free a dddns control block.  This block is used
558*83ee113eSDavid van Moolenbroek  * to pass and track the information associated with a DDNS update request.
559*83ee113eSDavid van Moolenbroek  */
560*83ee113eSDavid van Moolenbroek dhcp_ddns_cb_t *
ddns_cb_alloc(const char * file,int line)561*83ee113eSDavid van Moolenbroek ddns_cb_alloc(const char *file, int line)
562*83ee113eSDavid van Moolenbroek {
563*83ee113eSDavid van Moolenbroek 	dhcp_ddns_cb_t *ddns_cb;
564*83ee113eSDavid van Moolenbroek 	int i;
565*83ee113eSDavid van Moolenbroek 
566*83ee113eSDavid van Moolenbroek 	ddns_cb = dmalloc(sizeof(*ddns_cb), file, line);
567*83ee113eSDavid van Moolenbroek 	if (ddns_cb != NULL) {
568*83ee113eSDavid van Moolenbroek 		ISC_LIST_INIT(ddns_cb->zone_server_list);
569*83ee113eSDavid van Moolenbroek 		for (i = 0; i < DHCP_MAXNS; i++) {
570*83ee113eSDavid van Moolenbroek 			ISC_LINK_INIT(&ddns_cb->zone_addrs[i], link);
571*83ee113eSDavid van Moolenbroek 		}
572*83ee113eSDavid van Moolenbroek 	}
573*83ee113eSDavid van Moolenbroek 
574*83ee113eSDavid van Moolenbroek #if defined (DEBUG_DNS_UPDATES)
575*83ee113eSDavid van Moolenbroek 	log_info("%s(%d): Allocating ddns_cb=%p", file, line, ddns_cb);
576*83ee113eSDavid van Moolenbroek #endif
577*83ee113eSDavid van Moolenbroek 
578*83ee113eSDavid van Moolenbroek 	return(ddns_cb);
579*83ee113eSDavid van Moolenbroek }
580*83ee113eSDavid van Moolenbroek 
581*83ee113eSDavid van Moolenbroek void
ddns_cb_free(dhcp_ddns_cb_t * ddns_cb,const char * file,int line)582*83ee113eSDavid van Moolenbroek ddns_cb_free(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
583*83ee113eSDavid van Moolenbroek {
584*83ee113eSDavid van Moolenbroek #if defined (DEBUG_DNS_UPDATES)
585*83ee113eSDavid van Moolenbroek 	log_info("%s(%d): freeing ddns_cb=%p", file, line, ddns_cb);
586*83ee113eSDavid van Moolenbroek #endif
587*83ee113eSDavid van Moolenbroek 
588*83ee113eSDavid van Moolenbroek   	data_string_forget(&ddns_cb->fwd_name, file, line);
589*83ee113eSDavid van Moolenbroek 	data_string_forget(&ddns_cb->rev_name, file, line);
590*83ee113eSDavid van Moolenbroek 	data_string_forget(&ddns_cb->dhcid, file, line);
591*83ee113eSDavid van Moolenbroek 
592*83ee113eSDavid van Moolenbroek 	if (ddns_cb->zone != NULL) {
593*83ee113eSDavid van Moolenbroek 		forget_zone((struct dns_zone **)&ddns_cb->zone);
594*83ee113eSDavid van Moolenbroek 	}
595*83ee113eSDavid van Moolenbroek 
596*83ee113eSDavid van Moolenbroek 	/* Should be freed by now, check just in case. */
597*83ee113eSDavid van Moolenbroek 	if (ddns_cb->transaction != NULL)
598*83ee113eSDavid van Moolenbroek 		log_error("Impossible memory leak at %s:%d (attempt to free "
599*83ee113eSDavid van Moolenbroek 			  "DDNS Control Block before transaction).", MDL);
600*83ee113eSDavid van Moolenbroek 
601*83ee113eSDavid van Moolenbroek 	dfree(ddns_cb, file, line);
602*83ee113eSDavid van Moolenbroek }
603*83ee113eSDavid van Moolenbroek 
604*83ee113eSDavid van Moolenbroek void
ddns_cb_forget_zone(dhcp_ddns_cb_t * ddns_cb)605*83ee113eSDavid van Moolenbroek ddns_cb_forget_zone(dhcp_ddns_cb_t *ddns_cb)
606*83ee113eSDavid van Moolenbroek {
607*83ee113eSDavid van Moolenbroek 	int i;
608*83ee113eSDavid van Moolenbroek 
609*83ee113eSDavid van Moolenbroek 	forget_zone(&ddns_cb->zone);
610*83ee113eSDavid van Moolenbroek 	ddns_cb->zone_name[0] = 0;
611*83ee113eSDavid van Moolenbroek 	ISC_LIST_INIT(ddns_cb->zone_server_list);
612*83ee113eSDavid van Moolenbroek 	for (i = 0; i < DHCP_MAXNS; i++) {
613*83ee113eSDavid van Moolenbroek 		ISC_LINK_INIT(&ddns_cb->zone_addrs[i], link);
614*83ee113eSDavid van Moolenbroek 	}
615*83ee113eSDavid van Moolenbroek }
616*83ee113eSDavid van Moolenbroek 
find_tsig_key(ns_tsig_key ** key,const char * zname,struct dns_zone * zone)617*83ee113eSDavid van Moolenbroek isc_result_t find_tsig_key (ns_tsig_key **key, const char *zname,
618*83ee113eSDavid van Moolenbroek 			    struct dns_zone *zone)
619*83ee113eSDavid van Moolenbroek {
620*83ee113eSDavid van Moolenbroek 	ns_tsig_key *tkey;
621*83ee113eSDavid van Moolenbroek 
622*83ee113eSDavid van Moolenbroek 	if (!zone)
623*83ee113eSDavid van Moolenbroek 		return ISC_R_NOTFOUND;
624*83ee113eSDavid van Moolenbroek 
625*83ee113eSDavid van Moolenbroek 	if (!zone -> key) {
626*83ee113eSDavid van Moolenbroek 		return DHCP_R_KEY_UNKNOWN;
627*83ee113eSDavid van Moolenbroek 	}
628*83ee113eSDavid van Moolenbroek 
629*83ee113eSDavid van Moolenbroek 	if ((!zone -> key -> name ||
630*83ee113eSDavid van Moolenbroek 	     strlen (zone -> key -> name) > NS_MAXDNAME) ||
631*83ee113eSDavid van Moolenbroek 	    (!zone -> key -> algorithm ||
632*83ee113eSDavid van Moolenbroek 	     strlen (zone -> key -> algorithm) > NS_MAXDNAME) ||
633*83ee113eSDavid van Moolenbroek 	    (!zone -> key) ||
634*83ee113eSDavid van Moolenbroek 	    (!zone -> key -> key) ||
635*83ee113eSDavid van Moolenbroek 	    (zone -> key -> key -> len == 0)) {
636*83ee113eSDavid van Moolenbroek 		return DHCP_R_INVALIDKEY;
637*83ee113eSDavid van Moolenbroek 	}
638*83ee113eSDavid van Moolenbroek 	tkey = dmalloc (sizeof *tkey, MDL);
639*83ee113eSDavid van Moolenbroek 	if (!tkey) {
640*83ee113eSDavid van Moolenbroek 	      nomem:
641*83ee113eSDavid van Moolenbroek 		return ISC_R_NOMEMORY;
642*83ee113eSDavid van Moolenbroek 	}
643*83ee113eSDavid van Moolenbroek 	memset (tkey, 0, sizeof *tkey);
644*83ee113eSDavid van Moolenbroek 	tkey -> data = dmalloc (zone -> key -> key -> len, MDL);
645*83ee113eSDavid van Moolenbroek 	if (!tkey -> data) {
646*83ee113eSDavid van Moolenbroek 		dfree (tkey, MDL);
647*83ee113eSDavid van Moolenbroek 		goto nomem;
648*83ee113eSDavid van Moolenbroek 	}
649*83ee113eSDavid van Moolenbroek 	strcpy (tkey -> name, zone -> key -> name);
650*83ee113eSDavid van Moolenbroek 	strcpy (tkey -> alg, zone -> key -> algorithm);
651*83ee113eSDavid van Moolenbroek 	memcpy (tkey -> data,
652*83ee113eSDavid van Moolenbroek 		zone -> key -> key -> value, zone -> key -> key -> len);
653*83ee113eSDavid van Moolenbroek 	tkey -> len = zone -> key -> key -> len;
654*83ee113eSDavid van Moolenbroek 	*key = tkey;
655*83ee113eSDavid van Moolenbroek 	return ISC_R_SUCCESS;
656*83ee113eSDavid van Moolenbroek }
657*83ee113eSDavid van Moolenbroek 
tkey_free(ns_tsig_key ** key)658*83ee113eSDavid van Moolenbroek void tkey_free (ns_tsig_key **key)
659*83ee113eSDavid van Moolenbroek {
660*83ee113eSDavid van Moolenbroek 	if ((*key) -> data)
661*83ee113eSDavid van Moolenbroek 		dfree ((*key) -> data, MDL);
662*83ee113eSDavid van Moolenbroek 	dfree ((*key), MDL);
663*83ee113eSDavid van Moolenbroek 	*key = (ns_tsig_key *)0;
664*83ee113eSDavid van Moolenbroek }
665*83ee113eSDavid van Moolenbroek #endif
666*83ee113eSDavid van Moolenbroek 
remove_dns_zone(struct dns_zone * zone)667*83ee113eSDavid van Moolenbroek static isc_result_t remove_dns_zone (struct dns_zone *zone)
668*83ee113eSDavid van Moolenbroek {
669*83ee113eSDavid van Moolenbroek 	struct dns_zone *tz = NULL;
670*83ee113eSDavid van Moolenbroek 
671*83ee113eSDavid van Moolenbroek 	if (dns_zone_hash) {
672*83ee113eSDavid van Moolenbroek 		dns_zone_hash_lookup(&tz, dns_zone_hash, zone->name, 0, MDL);
673*83ee113eSDavid van Moolenbroek 		if (tz != NULL) {
674*83ee113eSDavid van Moolenbroek 			dns_zone_hash_delete(dns_zone_hash, tz->name, 0, MDL);
675*83ee113eSDavid van Moolenbroek 			dns_zone_dereference(&tz, MDL);
676*83ee113eSDavid van Moolenbroek 		}
677*83ee113eSDavid van Moolenbroek 	}
678*83ee113eSDavid van Moolenbroek 
679*83ee113eSDavid van Moolenbroek 	return (ISC_R_SUCCESS);
680*83ee113eSDavid van Moolenbroek }
681*83ee113eSDavid van Moolenbroek 
enter_dns_zone(struct dns_zone * zone)682*83ee113eSDavid van Moolenbroek isc_result_t enter_dns_zone (struct dns_zone *zone)
683*83ee113eSDavid van Moolenbroek {
684*83ee113eSDavid van Moolenbroek 	struct dns_zone *tz = (struct dns_zone *)0;
685*83ee113eSDavid van Moolenbroek 
686*83ee113eSDavid van Moolenbroek 	if (dns_zone_hash) {
687*83ee113eSDavid van Moolenbroek 		dns_zone_hash_lookup (&tz,
688*83ee113eSDavid van Moolenbroek 				      dns_zone_hash, zone -> name, 0, MDL);
689*83ee113eSDavid van Moolenbroek 		if (tz == zone) {
690*83ee113eSDavid van Moolenbroek 			dns_zone_dereference (&tz, MDL);
691*83ee113eSDavid van Moolenbroek 			return ISC_R_SUCCESS;
692*83ee113eSDavid van Moolenbroek 		}
693*83ee113eSDavid van Moolenbroek 		if (tz) {
694*83ee113eSDavid van Moolenbroek 			dns_zone_hash_delete (dns_zone_hash,
695*83ee113eSDavid van Moolenbroek 					      zone -> name, 0, MDL);
696*83ee113eSDavid van Moolenbroek 			dns_zone_dereference (&tz, MDL);
697*83ee113eSDavid van Moolenbroek 		}
698*83ee113eSDavid van Moolenbroek 	} else {
699*83ee113eSDavid van Moolenbroek 		if (!dns_zone_new_hash(&dns_zone_hash, DNS_HASH_SIZE, MDL))
700*83ee113eSDavid van Moolenbroek 			return ISC_R_NOMEMORY;
701*83ee113eSDavid van Moolenbroek 	}
702*83ee113eSDavid van Moolenbroek 
703*83ee113eSDavid van Moolenbroek 	dns_zone_hash_add (dns_zone_hash, zone -> name, 0, zone, MDL);
704*83ee113eSDavid van Moolenbroek 	return ISC_R_SUCCESS;
705*83ee113eSDavid van Moolenbroek }
706*83ee113eSDavid van Moolenbroek 
dns_zone_lookup(struct dns_zone ** zone,const char * name)707*83ee113eSDavid van Moolenbroek isc_result_t dns_zone_lookup (struct dns_zone **zone, const char *name)
708*83ee113eSDavid van Moolenbroek {
709*83ee113eSDavid van Moolenbroek 	int len;
710*83ee113eSDavid van Moolenbroek 	char *tname = (char *)0;
711*83ee113eSDavid van Moolenbroek 	isc_result_t status;
712*83ee113eSDavid van Moolenbroek 
713*83ee113eSDavid van Moolenbroek 	if (!dns_zone_hash)
714*83ee113eSDavid van Moolenbroek 		return ISC_R_NOTFOUND;
715*83ee113eSDavid van Moolenbroek 
716*83ee113eSDavid van Moolenbroek 	len = strlen (name);
717*83ee113eSDavid van Moolenbroek 	if (name [len - 1] != '.') {
718*83ee113eSDavid van Moolenbroek 		tname = dmalloc ((unsigned)len + 2, MDL);
719*83ee113eSDavid van Moolenbroek 		if (!tname)
720*83ee113eSDavid van Moolenbroek 			return ISC_R_NOMEMORY;
721*83ee113eSDavid van Moolenbroek 		strcpy (tname, name);
722*83ee113eSDavid van Moolenbroek 		tname [len] = '.';
723*83ee113eSDavid van Moolenbroek 		tname [len + 1] = 0;
724*83ee113eSDavid van Moolenbroek 		name = tname;
725*83ee113eSDavid van Moolenbroek 	}
726*83ee113eSDavid van Moolenbroek 	if (!dns_zone_hash_lookup (zone, dns_zone_hash, name, 0, MDL))
727*83ee113eSDavid van Moolenbroek 		status = ISC_R_NOTFOUND;
728*83ee113eSDavid van Moolenbroek 	else if ((*zone)->timeout && (*zone)->timeout < cur_time) {
729*83ee113eSDavid van Moolenbroek 		dns_zone_hash_delete(dns_zone_hash, (*zone)->name, 0, MDL);
730*83ee113eSDavid van Moolenbroek 		dns_zone_dereference(zone, MDL);
731*83ee113eSDavid van Moolenbroek 		status = ISC_R_NOTFOUND;
732*83ee113eSDavid van Moolenbroek 	} else
733*83ee113eSDavid van Moolenbroek 		status = ISC_R_SUCCESS;
734*83ee113eSDavid van Moolenbroek 
735*83ee113eSDavid van Moolenbroek 	if (tname)
736*83ee113eSDavid van Moolenbroek 		dfree (tname, MDL);
737*83ee113eSDavid van Moolenbroek 	return status;
738*83ee113eSDavid van Moolenbroek }
739*83ee113eSDavid van Moolenbroek 
dns_zone_dereference(ptr,file,line)740*83ee113eSDavid van Moolenbroek int dns_zone_dereference (ptr, file, line)
741*83ee113eSDavid van Moolenbroek 	struct dns_zone **ptr;
742*83ee113eSDavid van Moolenbroek 	const char *file;
743*83ee113eSDavid van Moolenbroek 	int line;
744*83ee113eSDavid van Moolenbroek {
745*83ee113eSDavid van Moolenbroek 	struct dns_zone *dns_zone;
746*83ee113eSDavid van Moolenbroek 
747*83ee113eSDavid van Moolenbroek 	if ((ptr == NULL) || (*ptr == NULL)) {
748*83ee113eSDavid van Moolenbroek 		log_error("%s(%d): null pointer", file, line);
749*83ee113eSDavid van Moolenbroek #if defined (POINTER_DEBUG)
750*83ee113eSDavid van Moolenbroek 		abort();
751*83ee113eSDavid van Moolenbroek #else
752*83ee113eSDavid van Moolenbroek 		return (0);
753*83ee113eSDavid van Moolenbroek #endif
754*83ee113eSDavid van Moolenbroek 	}
755*83ee113eSDavid van Moolenbroek 
756*83ee113eSDavid van Moolenbroek 	dns_zone = *ptr;
757*83ee113eSDavid van Moolenbroek 	*ptr = NULL;
758*83ee113eSDavid van Moolenbroek 	--dns_zone->refcnt;
759*83ee113eSDavid van Moolenbroek 	rc_register(file, line, ptr, dns_zone, dns_zone->refcnt, 1, RC_MISC);
760*83ee113eSDavid van Moolenbroek 	if (dns_zone->refcnt > 0)
761*83ee113eSDavid van Moolenbroek 		return (1);
762*83ee113eSDavid van Moolenbroek 
763*83ee113eSDavid van Moolenbroek 	if (dns_zone->refcnt < 0) {
764*83ee113eSDavid van Moolenbroek 		log_error("%s(%d): negative refcnt!", file, line);
765*83ee113eSDavid van Moolenbroek #if defined (DEBUG_RC_HISTORY)
766*83ee113eSDavid van Moolenbroek 		dump_rc_history(dns_zone);
767*83ee113eSDavid van Moolenbroek #endif
768*83ee113eSDavid van Moolenbroek #if defined (POINTER_DEBUG)
769*83ee113eSDavid van Moolenbroek 		abort();
770*83ee113eSDavid van Moolenbroek #else
771*83ee113eSDavid van Moolenbroek 		return (0);
772*83ee113eSDavid van Moolenbroek #endif
773*83ee113eSDavid van Moolenbroek 	}
774*83ee113eSDavid van Moolenbroek 
775*83ee113eSDavid van Moolenbroek 	if (dns_zone->name)
776*83ee113eSDavid van Moolenbroek 		dfree(dns_zone->name, file, line);
777*83ee113eSDavid van Moolenbroek 	if (dns_zone->key)
778*83ee113eSDavid van Moolenbroek 		omapi_auth_key_dereference(&dns_zone->key, file, line);
779*83ee113eSDavid van Moolenbroek 	if (dns_zone->primary)
780*83ee113eSDavid van Moolenbroek 		option_cache_dereference(&dns_zone->primary, file, line);
781*83ee113eSDavid van Moolenbroek 	if (dns_zone->secondary)
782*83ee113eSDavid van Moolenbroek 		option_cache_dereference(&dns_zone->secondary, file, line);
783*83ee113eSDavid van Moolenbroek 	if (dns_zone->primary6)
784*83ee113eSDavid van Moolenbroek 		option_cache_dereference(&dns_zone->primary6, file, line);
785*83ee113eSDavid van Moolenbroek 	if (dns_zone->secondary6)
786*83ee113eSDavid van Moolenbroek 		option_cache_dereference(&dns_zone->secondary6, file, line);
787*83ee113eSDavid van Moolenbroek 	dfree(dns_zone, file, line);
788*83ee113eSDavid van Moolenbroek 	return (1);
789*83ee113eSDavid van Moolenbroek }
790*83ee113eSDavid van Moolenbroek 
791*83ee113eSDavid van Moolenbroek #if defined (NSUPDATE)
792*83ee113eSDavid van Moolenbroek #if defined (DNS_ZONE_LOOKUP)
793*83ee113eSDavid van Moolenbroek 
794*83ee113eSDavid van Moolenbroek /* Helper function to copy the address from an rdataset to
795*83ee113eSDavid van Moolenbroek  * the nameserver control block.  Mostly to avoid really long
796*83ee113eSDavid van Moolenbroek  * lines in the nested for loops
797*83ee113eSDavid van Moolenbroek  */
798*83ee113eSDavid van Moolenbroek static void
zone_addr_to_ns(dhcp_ddns_ns_t * ns_cb,dns_rdataset_t * rdataset)799*83ee113eSDavid van Moolenbroek zone_addr_to_ns(dhcp_ddns_ns_t *ns_cb,
800*83ee113eSDavid van Moolenbroek 		dns_rdataset_t *rdataset)
801*83ee113eSDavid van Moolenbroek {
802*83ee113eSDavid van Moolenbroek 	dns_rdata_t rdata;
803*83ee113eSDavid van Moolenbroek 	dns_rdata_in_a_t a;
804*83ee113eSDavid van Moolenbroek 	dns_rdata_in_aaaa_t aaaa;
805*83ee113eSDavid van Moolenbroek 
806*83ee113eSDavid van Moolenbroek 	dns_rdata_init(&rdata);
807*83ee113eSDavid van Moolenbroek 	dns_rdataset_current(rdataset, &rdata);
808*83ee113eSDavid van Moolenbroek 	switch (rdataset->type) {
809*83ee113eSDavid van Moolenbroek 	case dns_rdatatype_a:
810*83ee113eSDavid van Moolenbroek 		(void) dns_rdata_tostruct(&rdata, &a, NULL);
811*83ee113eSDavid van Moolenbroek 		memcpy(&ns_cb->addrs[ns_cb->num_addrs], &a.in_addr, 4);
812*83ee113eSDavid van Moolenbroek 		ns_cb->num_addrs++;
813*83ee113eSDavid van Moolenbroek 		dns_rdata_freestruct(&a);
814*83ee113eSDavid van Moolenbroek 		break;
815*83ee113eSDavid van Moolenbroek 	case dns_rdatatype_aaaa:
816*83ee113eSDavid van Moolenbroek 		(void) dns_rdata_tostruct(&rdata, &aaaa, NULL);
817*83ee113eSDavid van Moolenbroek 		memcpy(&ns_cb->addrs6[ns_cb->num_addrs6], &aaaa.in6_addr, 16);
818*83ee113eSDavid van Moolenbroek 		ns_cb->num_addrs6++;
819*83ee113eSDavid van Moolenbroek 		dns_rdata_freestruct(&aaaa);
820*83ee113eSDavid van Moolenbroek 		break;
821*83ee113eSDavid van Moolenbroek 	default:
822*83ee113eSDavid van Moolenbroek 		break;
823*83ee113eSDavid van Moolenbroek 	}
824*83ee113eSDavid van Moolenbroek 
825*83ee113eSDavid van Moolenbroek 	if ((ns_cb->ttl == 0) || (ns_cb->ttl > rdataset->ttl))
826*83ee113eSDavid van Moolenbroek 		ns_cb->ttl = rdataset->ttl;
827*83ee113eSDavid van Moolenbroek }
828*83ee113eSDavid van Moolenbroek 
829*83ee113eSDavid van Moolenbroek /*
830*83ee113eSDavid van Moolenbroek  * The following three routines co-operate to find the addresses of
831*83ee113eSDavid van Moolenbroek  * the nameservers to use for a zone if we don't have a zone statement.
832*83ee113eSDavid van Moolenbroek  * We strongly suggest the use of a zone statement to avoid problmes
833*83ee113eSDavid van Moolenbroek  * and to allow for the use of TSIG and therefore better security, but
834*83ee113eSDavid van Moolenbroek  * include this functionality for those that don't want such statements.
835*83ee113eSDavid van Moolenbroek  *
836*83ee113eSDavid van Moolenbroek  * find_zone_start(ddns_cb, direction)
837*83ee113eSDavid van Moolenbroek  * This is the first of the routines, it is called from the rest of
838*83ee113eSDavid van Moolenbroek  * the ddns code when we have received a request for DDNS for a name
839*83ee113eSDavid van Moolenbroek  * and don't have a zone entry that would cover that name.  The name
840*83ee113eSDavid van Moolenbroek  * is in the ddns_cb as specified by the direction (forward or reverse).
841*83ee113eSDavid van Moolenbroek  * The start function pulls the name out and constructs the name server
842*83ee113eSDavid van Moolenbroek  * block then starts the process by calling the DNS client code.
843*83ee113eSDavid van Moolenbroek  *
844*83ee113eSDavid van Moolenbroek  * find_zone_ns(taskp, eventp)
845*83ee113eSDavid van Moolenbroek  * This is the second step of the process.  The DNS client code will
846*83ee113eSDavid van Moolenbroek  * call this when it has gotten a response or timed out.  If the response
847*83ee113eSDavid van Moolenbroek  * doesn't have a list of nameservers we remove another label from the
848*83ee113eSDavid van Moolenbroek  * zone name and try again.  If the response does include a list of
849*83ee113eSDavid van Moolenbroek  * nameservers we start walking through the list attempting to get
850*83ee113eSDavid van Moolenbroek  * addresses for the nameservers.
851*83ee113eSDavid van Moolenbroek  *
852*83ee113eSDavid van Moolenbroek  * find_zone_addrs(taskp, eventp)
853*83ee113eSDavid van Moolenbroek  * This is the third step of the process.  In find_zone_ns we got
854*83ee113eSDavid van Moolenbroek  * a list of nameserves and started walking through them.  This continues
855*83ee113eSDavid van Moolenbroek  * the walk and if we get back any addresses it adds them to our list.
856*83ee113eSDavid van Moolenbroek  * When we get enough addresses or run out of nameservers we construct
857*83ee113eSDavid van Moolenbroek  * a zone entry and insert it into the zone hash for the rest of the
858*83ee113eSDavid van Moolenbroek  * DDNS code to use.
859*83ee113eSDavid van Moolenbroek  */
860*83ee113eSDavid van Moolenbroek static void
find_zone_addrs(isc_task_t * taskp,isc_event_t * eventp)861*83ee113eSDavid van Moolenbroek find_zone_addrs(isc_task_t *taskp,
862*83ee113eSDavid van Moolenbroek 		isc_event_t *eventp)
863*83ee113eSDavid van Moolenbroek {
864*83ee113eSDavid van Moolenbroek 	dns_clientresevent_t *ddns_event = (dns_clientresevent_t *)eventp;
865*83ee113eSDavid van Moolenbroek 	dhcp_ddns_ns_t *ns_cb = (dhcp_ddns_ns_t *)eventp->ev_arg;
866*83ee113eSDavid van Moolenbroek 	dns_name_t *ns_name = NULL;
867*83ee113eSDavid van Moolenbroek 	dns_rdataset_t *rdataset;
868*83ee113eSDavid van Moolenbroek 	isc_result_t result;
869*83ee113eSDavid van Moolenbroek 	dns_name_t *name;
870*83ee113eSDavid van Moolenbroek 	dns_rdata_t rdata = DNS_RDATA_INIT;
871*83ee113eSDavid van Moolenbroek 	dns_rdata_ns_t ns;
872*83ee113eSDavid van Moolenbroek 
873*83ee113eSDavid van Moolenbroek 
874*83ee113eSDavid van Moolenbroek 	/* the transaction is done, get rid of the tag */
875*83ee113eSDavid van Moolenbroek 	dns_client_destroyrestrans(&ns_cb->transaction);
876*83ee113eSDavid van Moolenbroek 
877*83ee113eSDavid van Moolenbroek 	/* If we succeeded we try and extract the addresses, if we can
878*83ee113eSDavid van Moolenbroek 	 * and we have enough we are done.  If we didn't succeed or
879*83ee113eSDavid van Moolenbroek 	 * we don't have enough addresses afterwards we drop through
880*83ee113eSDavid van Moolenbroek 	 * and try the next item on the list.
881*83ee113eSDavid van Moolenbroek 	 */
882*83ee113eSDavid van Moolenbroek 	if (ddns_event->result == ISC_R_SUCCESS) {
883*83ee113eSDavid van Moolenbroek 
884*83ee113eSDavid van Moolenbroek 		for (name = ISC_LIST_HEAD(ddns_event->answerlist);
885*83ee113eSDavid van Moolenbroek 		     name != NULL;
886*83ee113eSDavid van Moolenbroek 		     name = ISC_LIST_NEXT(name, link)) {
887*83ee113eSDavid van Moolenbroek 
888*83ee113eSDavid van Moolenbroek 			for (rdataset = ISC_LIST_HEAD(name->list);
889*83ee113eSDavid van Moolenbroek 			     rdataset != NULL;
890*83ee113eSDavid van Moolenbroek 			     rdataset = ISC_LIST_NEXT(rdataset, link)) {
891*83ee113eSDavid van Moolenbroek 
892*83ee113eSDavid van Moolenbroek 				for (result = dns_rdataset_first(rdataset);
893*83ee113eSDavid van Moolenbroek 				     result == ISC_R_SUCCESS;
894*83ee113eSDavid van Moolenbroek 				     result = dns_rdataset_next(rdataset)) {
895*83ee113eSDavid van Moolenbroek 
896*83ee113eSDavid van Moolenbroek 					/* add address to cb */
897*83ee113eSDavid van Moolenbroek 					zone_addr_to_ns(ns_cb, rdataset);
898*83ee113eSDavid van Moolenbroek 
899*83ee113eSDavid van Moolenbroek 					/* We are done if we have
900*83ee113eSDavid van Moolenbroek 					 * enough addresses
901*83ee113eSDavid van Moolenbroek 					 */
902*83ee113eSDavid van Moolenbroek 					if (ns_cb->num_addrs +
903*83ee113eSDavid van Moolenbroek 					    ns_cb->num_addrs6 >= DHCP_MAXNS)
904*83ee113eSDavid van Moolenbroek 						goto done;
905*83ee113eSDavid van Moolenbroek 				}
906*83ee113eSDavid van Moolenbroek 			}
907*83ee113eSDavid van Moolenbroek 		}
908*83ee113eSDavid van Moolenbroek 	}
909*83ee113eSDavid van Moolenbroek 
910*83ee113eSDavid van Moolenbroek 	/* We need more addresses.
911*83ee113eSDavid van Moolenbroek 	 * We restart the loop we were in before.
912*83ee113eSDavid van Moolenbroek 	 */
913*83ee113eSDavid van Moolenbroek 
914*83ee113eSDavid van Moolenbroek 	for (ns_name = ns_cb->ns_name;
915*83ee113eSDavid van Moolenbroek 	     ns_name != NULL;
916*83ee113eSDavid van Moolenbroek 	     ns_name = ISC_LIST_NEXT(ns_name, link)) {
917*83ee113eSDavid van Moolenbroek 
918*83ee113eSDavid van Moolenbroek 		if (ns_name == ns_cb->ns_name) {
919*83ee113eSDavid van Moolenbroek 			/* first time through, use saved state */
920*83ee113eSDavid van Moolenbroek 			rdataset = ns_cb->rdataset;
921*83ee113eSDavid van Moolenbroek 		} else {
922*83ee113eSDavid van Moolenbroek 			rdataset = ISC_LIST_HEAD(ns_name->list);
923*83ee113eSDavid van Moolenbroek 		}
924*83ee113eSDavid van Moolenbroek 
925*83ee113eSDavid van Moolenbroek 		for (;
926*83ee113eSDavid van Moolenbroek 		     rdataset != NULL;
927*83ee113eSDavid van Moolenbroek 		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
928*83ee113eSDavid van Moolenbroek 
929*83ee113eSDavid van Moolenbroek 			if (rdataset->type != dns_rdatatype_ns)
930*83ee113eSDavid van Moolenbroek 				continue;
931*83ee113eSDavid van Moolenbroek 			dns_rdata_init(&rdata);
932*83ee113eSDavid van Moolenbroek 
933*83ee113eSDavid van Moolenbroek 			if (rdataset == ns_cb->rdataset) {
934*83ee113eSDavid van Moolenbroek 				/* first time through use the saved state */
935*83ee113eSDavid van Moolenbroek 				if (ns_cb->rdtype == dns_rdatatype_a) {
936*83ee113eSDavid van Moolenbroek 					ns_cb->rdtype = dns_rdatatype_aaaa;
937*83ee113eSDavid van Moolenbroek 				} else {
938*83ee113eSDavid van Moolenbroek 					ns_cb->rdtype = dns_rdatatype_a;
939*83ee113eSDavid van Moolenbroek 					if (dns_rdataset_next(rdataset) !=
940*83ee113eSDavid van Moolenbroek 					    ISC_R_SUCCESS)
941*83ee113eSDavid van Moolenbroek 						continue;
942*83ee113eSDavid van Moolenbroek 				}
943*83ee113eSDavid van Moolenbroek 			} else {
944*83ee113eSDavid van Moolenbroek 				if ((!dns_rdataset_isassociated(rdataset)) ||
945*83ee113eSDavid van Moolenbroek 				    (dns_rdataset_first(rdataset) !=
946*83ee113eSDavid van Moolenbroek 				     ISC_R_SUCCESS))
947*83ee113eSDavid van Moolenbroek 					continue;
948*83ee113eSDavid van Moolenbroek 			}
949*83ee113eSDavid van Moolenbroek 
950*83ee113eSDavid van Moolenbroek 			dns_rdataset_current(rdataset, &rdata);
951*83ee113eSDavid van Moolenbroek 			if (dns_rdata_tostruct(&rdata, &ns, NULL) !=
952*83ee113eSDavid van Moolenbroek 			    ISC_R_SUCCESS)
953*83ee113eSDavid van Moolenbroek 				continue;
954*83ee113eSDavid van Moolenbroek 
955*83ee113eSDavid van Moolenbroek 			/* Save our current state */
956*83ee113eSDavid van Moolenbroek 			ns_cb->ns_name = ns_name;
957*83ee113eSDavid van Moolenbroek 			ns_cb->rdataset = rdataset;
958*83ee113eSDavid van Moolenbroek 
959*83ee113eSDavid van Moolenbroek 			/* And call out to DNS */
960*83ee113eSDavid van Moolenbroek 			result = zone_resolve(dhcp_gbl_ctx.dnsclient, &ns.name,
961*83ee113eSDavid van Moolenbroek 					      dns_rdataclass_in,
962*83ee113eSDavid van Moolenbroek 					      ns_cb->rdtype,
963*83ee113eSDavid van Moolenbroek 					      DNS_CLIENTRESOPT_NODNSSEC,
964*83ee113eSDavid van Moolenbroek 					      dhcp_gbl_ctx.task,
965*83ee113eSDavid van Moolenbroek 					      find_zone_addrs,
966*83ee113eSDavid van Moolenbroek 					      (void *)ns_cb,
967*83ee113eSDavid van Moolenbroek 					      &ns_cb->transaction);
968*83ee113eSDavid van Moolenbroek 
969*83ee113eSDavid van Moolenbroek 			/* do we need to clean this? */
970*83ee113eSDavid van Moolenbroek 			dns_rdata_freestruct(&ns);
971*83ee113eSDavid van Moolenbroek 
972*83ee113eSDavid van Moolenbroek 			if (result == ISC_R_SUCCESS)
973*83ee113eSDavid van Moolenbroek 				/* we have started the next step, cleanup
974*83ee113eSDavid van Moolenbroek 				 * the structures associated with this call
975*83ee113eSDavid van Moolenbroek 				 * but leave the cb for the next round
976*83ee113eSDavid van Moolenbroek 				 */
977*83ee113eSDavid van Moolenbroek 				goto cleanup;
978*83ee113eSDavid van Moolenbroek 
979*83ee113eSDavid van Moolenbroek 			log_error("find_zone_addrs: unable to continue "
980*83ee113eSDavid van Moolenbroek 				  "resolve: %s %s",
981*83ee113eSDavid van Moolenbroek 				  ns_cb->zname,
982*83ee113eSDavid van Moolenbroek 				  isc_result_totext(result));
983*83ee113eSDavid van Moolenbroek 
984*83ee113eSDavid van Moolenbroek 			/* The call to start a resolve transaction failed,
985*83ee113eSDavid van Moolenbroek 			 * should we try to continue with any other names?
986*83ee113eSDavid van Moolenbroek 			 * For now let's not, but let's use whatever we
987*83ee113eSDavid van Moolenbroek 			 * may already have.
988*83ee113eSDavid van Moolenbroek 			 */
989*83ee113eSDavid van Moolenbroek 			goto done;
990*83ee113eSDavid van Moolenbroek 		}
991*83ee113eSDavid van Moolenbroek 	}
992*83ee113eSDavid van Moolenbroek 
993*83ee113eSDavid van Moolenbroek  done:
994*83ee113eSDavid van Moolenbroek 	/* we've either gotten our max number of addresses or
995*83ee113eSDavid van Moolenbroek 	 * run out of nameservers to try.  Convert the cb into
996*83ee113eSDavid van Moolenbroek 	 * a zone and insert it into the zone hash.  Then
997*83ee113eSDavid van Moolenbroek 	 * we need to clean up the saved state.
998*83ee113eSDavid van Moolenbroek 	 */
999*83ee113eSDavid van Moolenbroek 	if ((ns_cb->num_addrs != 0) ||
1000*83ee113eSDavid van Moolenbroek 	    (ns_cb->num_addrs6 != 0))
1001*83ee113eSDavid van Moolenbroek 		cache_found_zone(ns_cb);
1002*83ee113eSDavid van Moolenbroek 
1003*83ee113eSDavid van Moolenbroek 	dns_client_freeresanswer(dhcp_gbl_ctx.dnsclient,
1004*83ee113eSDavid van Moolenbroek 				 &ns_cb->eventp->answerlist);
1005*83ee113eSDavid van Moolenbroek 	isc_event_free((isc_event_t **)&ns_cb->eventp);
1006*83ee113eSDavid van Moolenbroek 
1007*83ee113eSDavid van Moolenbroek 	remove_from_ns_queue(ns_cb);
1008*83ee113eSDavid van Moolenbroek 	data_string_forget(&ns_cb->oname, MDL);
1009*83ee113eSDavid van Moolenbroek 	dfree(ns_cb, MDL);
1010*83ee113eSDavid van Moolenbroek 
1011*83ee113eSDavid van Moolenbroek  cleanup:
1012*83ee113eSDavid van Moolenbroek 	/* cleanup any of the new state information */
1013*83ee113eSDavid van Moolenbroek 
1014*83ee113eSDavid van Moolenbroek 	dns_client_freeresanswer(dhcp_gbl_ctx.dnsclient,
1015*83ee113eSDavid van Moolenbroek 				 &ddns_event->answerlist);
1016*83ee113eSDavid van Moolenbroek 	isc_event_free(&eventp);
1017*83ee113eSDavid van Moolenbroek 
1018*83ee113eSDavid van Moolenbroek 	return;
1019*83ee113eSDavid van Moolenbroek 
1020*83ee113eSDavid van Moolenbroek }
1021*83ee113eSDavid van Moolenbroek 
1022*83ee113eSDavid van Moolenbroek /*
1023*83ee113eSDavid van Moolenbroek  * Routine to continue the process of finding a nameserver via the DNS
1024*83ee113eSDavid van Moolenbroek  * This is routine is called when we are still trying to get a list
1025*83ee113eSDavid van Moolenbroek  * of nameservers to process.
1026*83ee113eSDavid van Moolenbroek  */
1027*83ee113eSDavid van Moolenbroek 
1028*83ee113eSDavid van Moolenbroek static void
find_zone_ns(isc_task_t * taskp,isc_event_t * eventp)1029*83ee113eSDavid van Moolenbroek find_zone_ns(isc_task_t *taskp,
1030*83ee113eSDavid van Moolenbroek 	     isc_event_t *eventp)
1031*83ee113eSDavid van Moolenbroek {
1032*83ee113eSDavid van Moolenbroek 	dns_clientresevent_t *ddns_event = (dns_clientresevent_t *)eventp;
1033*83ee113eSDavid van Moolenbroek 	dhcp_ddns_ns_t *ns_cb = (dhcp_ddns_ns_t *)eventp->ev_arg;
1034*83ee113eSDavid van Moolenbroek 	dns_fixedname_t zname0;
1035*83ee113eSDavid van Moolenbroek 	dns_name_t *zname = NULL, *ns_name = NULL;
1036*83ee113eSDavid van Moolenbroek 	dns_rdataset_t *rdataset;
1037*83ee113eSDavid van Moolenbroek 	isc_result_t result;
1038*83ee113eSDavid van Moolenbroek 	dns_rdata_t rdata = DNS_RDATA_INIT;
1039*83ee113eSDavid van Moolenbroek 	dns_rdata_ns_t ns;
1040*83ee113eSDavid van Moolenbroek 
1041*83ee113eSDavid van Moolenbroek 	/* the transaction is done, get rid of the tag */
1042*83ee113eSDavid van Moolenbroek 	dns_client_destroyrestrans(&ns_cb->transaction);
1043*83ee113eSDavid van Moolenbroek 
1044*83ee113eSDavid van Moolenbroek 	if (ddns_event->result != ISC_R_SUCCESS) {
1045*83ee113eSDavid van Moolenbroek 		/* We didn't find any nameservers, try again */
1046*83ee113eSDavid van Moolenbroek 
1047*83ee113eSDavid van Moolenbroek 		/* Remove a label and continue */
1048*83ee113eSDavid van Moolenbroek 		ns_cb->zname = strchr(ns_cb->zname, '.');
1049*83ee113eSDavid van Moolenbroek 		if ((ns_cb->zname == NULL) ||
1050*83ee113eSDavid van Moolenbroek 		    (ns_cb->zname[1] == 0)) {
1051*83ee113eSDavid van Moolenbroek 			/* No more labels, all done */
1052*83ee113eSDavid van Moolenbroek 			goto cleanup;
1053*83ee113eSDavid van Moolenbroek 		}
1054*83ee113eSDavid van Moolenbroek 		ns_cb->zname++;
1055*83ee113eSDavid van Moolenbroek 
1056*83ee113eSDavid van Moolenbroek 		/* Create a DNS version of the zone name and call the
1057*83ee113eSDavid van Moolenbroek 		 * resolver code */
1058*83ee113eSDavid van Moolenbroek 		if (((result = dhcp_isc_name((unsigned char *)ns_cb->zname,
1059*83ee113eSDavid van Moolenbroek 					     &zname0, &zname))
1060*83ee113eSDavid van Moolenbroek 		     != ISC_R_SUCCESS) ||
1061*83ee113eSDavid van Moolenbroek 		    ((result = zone_resolve(dhcp_gbl_ctx.dnsclient,
1062*83ee113eSDavid van Moolenbroek 					    zname, dns_rdataclass_in,
1063*83ee113eSDavid van Moolenbroek 					    dns_rdatatype_ns,
1064*83ee113eSDavid van Moolenbroek 					    DNS_CLIENTRESOPT_NODNSSEC,
1065*83ee113eSDavid van Moolenbroek 					    dhcp_gbl_ctx.task,
1066*83ee113eSDavid van Moolenbroek 					    find_zone_ns,
1067*83ee113eSDavid van Moolenbroek 					    (void *)ns_cb,
1068*83ee113eSDavid van Moolenbroek 					    &ns_cb->transaction))
1069*83ee113eSDavid van Moolenbroek 		     != ISC_R_SUCCESS)) {
1070*83ee113eSDavid van Moolenbroek 			log_error("find_zone_ns: Unable to build "
1071*83ee113eSDavid van Moolenbroek 				  "name or start resolve: %s %s",
1072*83ee113eSDavid van Moolenbroek 				  ns_cb->zname,
1073*83ee113eSDavid van Moolenbroek 				  isc_result_totext(result));
1074*83ee113eSDavid van Moolenbroek 			goto cleanup;
1075*83ee113eSDavid van Moolenbroek 		}
1076*83ee113eSDavid van Moolenbroek 
1077*83ee113eSDavid van Moolenbroek 		/* we have successfully started the next iteration
1078*83ee113eSDavid van Moolenbroek 		 * of this step, clean up from the call and continue */
1079*83ee113eSDavid van Moolenbroek                 dns_client_freeresanswer(dhcp_gbl_ctx.dnsclient,
1080*83ee113eSDavid van Moolenbroek                                          &ddns_event->answerlist);
1081*83ee113eSDavid van Moolenbroek 		isc_event_free(&eventp);
1082*83ee113eSDavid van Moolenbroek 		return;
1083*83ee113eSDavid van Moolenbroek 	}
1084*83ee113eSDavid van Moolenbroek 
1085*83ee113eSDavid van Moolenbroek 	/* We did get a set of nameservers, save the information and
1086*83ee113eSDavid van Moolenbroek 	 * start trying to get addresses
1087*83ee113eSDavid van Moolenbroek 	 */
1088*83ee113eSDavid van Moolenbroek 	ns_cb->eventp = ddns_event;
1089*83ee113eSDavid van Moolenbroek 	for (ns_name = ISC_LIST_HEAD(ddns_event->answerlist);
1090*83ee113eSDavid van Moolenbroek 	     ns_name != NULL;
1091*83ee113eSDavid van Moolenbroek 	     ns_name = ISC_LIST_NEXT(ns_name, link)) {
1092*83ee113eSDavid van Moolenbroek 
1093*83ee113eSDavid van Moolenbroek 		for (rdataset = ISC_LIST_HEAD(ns_name->list);
1094*83ee113eSDavid van Moolenbroek 		     rdataset != NULL;
1095*83ee113eSDavid van Moolenbroek 		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
1096*83ee113eSDavid van Moolenbroek 
1097*83ee113eSDavid van Moolenbroek 			if (rdataset->type != dns_rdatatype_ns)
1098*83ee113eSDavid van Moolenbroek 				continue;
1099*83ee113eSDavid van Moolenbroek 
1100*83ee113eSDavid van Moolenbroek 			if ((!dns_rdataset_isassociated(rdataset)) ||
1101*83ee113eSDavid van Moolenbroek 			    (dns_rdataset_first(rdataset) !=
1102*83ee113eSDavid van Moolenbroek 			     ISC_R_SUCCESS))
1103*83ee113eSDavid van Moolenbroek 				continue;
1104*83ee113eSDavid van Moolenbroek 
1105*83ee113eSDavid van Moolenbroek 			dns_rdataset_current(rdataset, &rdata);
1106*83ee113eSDavid van Moolenbroek 			if (dns_rdata_tostruct(&rdata, &ns, NULL) !=
1107*83ee113eSDavid van Moolenbroek 			    ISC_R_SUCCESS)
1108*83ee113eSDavid van Moolenbroek 				continue;
1109*83ee113eSDavid van Moolenbroek 
1110*83ee113eSDavid van Moolenbroek 			/* Save our current state */
1111*83ee113eSDavid van Moolenbroek 			ns_cb->ns_name = ns_name;
1112*83ee113eSDavid van Moolenbroek 			ns_cb->rdataset = rdataset;
1113*83ee113eSDavid van Moolenbroek 
1114*83ee113eSDavid van Moolenbroek 			/* And call out to DNS */
1115*83ee113eSDavid van Moolenbroek 			result = zone_resolve(dhcp_gbl_ctx.dnsclient, &ns.name,
1116*83ee113eSDavid van Moolenbroek 					      dns_rdataclass_in,
1117*83ee113eSDavid van Moolenbroek 					      ns_cb->rdtype,
1118*83ee113eSDavid van Moolenbroek 					      DNS_CLIENTRESOPT_NODNSSEC,
1119*83ee113eSDavid van Moolenbroek 					      dhcp_gbl_ctx.task,
1120*83ee113eSDavid van Moolenbroek 					      find_zone_addrs,
1121*83ee113eSDavid van Moolenbroek 					      (void *)ns_cb,
1122*83ee113eSDavid van Moolenbroek 					      &ns_cb->transaction);
1123*83ee113eSDavid van Moolenbroek 
1124*83ee113eSDavid van Moolenbroek 			/* do we need to clean this? */
1125*83ee113eSDavid van Moolenbroek 			dns_rdata_freestruct(&ns);
1126*83ee113eSDavid van Moolenbroek 
1127*83ee113eSDavid van Moolenbroek 			if (result == ISC_R_SUCCESS)
1128*83ee113eSDavid van Moolenbroek 				/* We have successfully started the next step
1129*83ee113eSDavid van Moolenbroek 				 * we don't cleanup the eventp block as we are
1130*83ee113eSDavid van Moolenbroek 				 * still using it.
1131*83ee113eSDavid van Moolenbroek 				 */
1132*83ee113eSDavid van Moolenbroek 				return;
1133*83ee113eSDavid van Moolenbroek 
1134*83ee113eSDavid van Moolenbroek 			log_error("find_zone_ns: unable to continue "
1135*83ee113eSDavid van Moolenbroek 				  "resolve: %s %s",
1136*83ee113eSDavid van Moolenbroek 				  ns_cb->zname,
1137*83ee113eSDavid van Moolenbroek 				  isc_result_totext(result));
1138*83ee113eSDavid van Moolenbroek 
1139*83ee113eSDavid van Moolenbroek 			/* The call to start a resolve transaction failed,
1140*83ee113eSDavid van Moolenbroek 			 * should we try to continue with any other names?
1141*83ee113eSDavid van Moolenbroek 			 * For now let's not
1142*83ee113eSDavid van Moolenbroek 			 */
1143*83ee113eSDavid van Moolenbroek 			goto cleanup;
1144*83ee113eSDavid van Moolenbroek 		}
1145*83ee113eSDavid van Moolenbroek 	}
1146*83ee113eSDavid van Moolenbroek 
1147*83ee113eSDavid van Moolenbroek  cleanup:
1148*83ee113eSDavid van Moolenbroek 	/* When we add a queue to manage the DDNS
1149*83ee113eSDavid van Moolenbroek 	 * requests we will need to remove any that
1150*83ee113eSDavid van Moolenbroek 	 * were waiting for this resolution */
1151*83ee113eSDavid van Moolenbroek 
1152*83ee113eSDavid van Moolenbroek 	dns_client_freeresanswer(dhcp_gbl_ctx.dnsclient,
1153*83ee113eSDavid van Moolenbroek 				 &ddns_event->answerlist);
1154*83ee113eSDavid van Moolenbroek 	isc_event_free(&eventp);
1155*83ee113eSDavid van Moolenbroek 
1156*83ee113eSDavid van Moolenbroek 	remove_from_ns_queue(ns_cb);
1157*83ee113eSDavid van Moolenbroek 
1158*83ee113eSDavid van Moolenbroek 	data_string_forget(&ns_cb->oname, MDL);
1159*83ee113eSDavid van Moolenbroek 	dfree(ns_cb, MDL);
1160*83ee113eSDavid van Moolenbroek 	return;
1161*83ee113eSDavid van Moolenbroek 
1162*83ee113eSDavid van Moolenbroek }
1163*83ee113eSDavid van Moolenbroek 
1164*83ee113eSDavid van Moolenbroek /*
1165*83ee113eSDavid van Moolenbroek  * Start the process of finding nameservers via the DNS because
1166*83ee113eSDavid van Moolenbroek  * we don't have a zone entry already.
1167*83ee113eSDavid van Moolenbroek  * We construct a control block and fill in the DDNS name.  As
1168*83ee113eSDavid van Moolenbroek  * the process continues we shall move the zname pointer to
1169*83ee113eSDavid van Moolenbroek  * indicate which labels we are still using.  The rest of
1170*83ee113eSDavid van Moolenbroek  * the control block will be filled in as we continue processing.
1171*83ee113eSDavid van Moolenbroek  */
1172*83ee113eSDavid van Moolenbroek static isc_result_t
find_zone_start(dhcp_ddns_cb_t * ddns_cb,int direction)1173*83ee113eSDavid van Moolenbroek find_zone_start(dhcp_ddns_cb_t *ddns_cb, int direction)
1174*83ee113eSDavid van Moolenbroek {
1175*83ee113eSDavid van Moolenbroek 	isc_result_t status = ISC_R_NOTFOUND;
1176*83ee113eSDavid van Moolenbroek 	dhcp_ddns_ns_t *ns_cb;
1177*83ee113eSDavid van Moolenbroek 	dns_fixedname_t zname0;
1178*83ee113eSDavid van Moolenbroek 	dns_name_t *zname = NULL;
1179*83ee113eSDavid van Moolenbroek 
1180*83ee113eSDavid van Moolenbroek 	/*
1181*83ee113eSDavid van Moolenbroek 	 * We don't validate np as that was already done in find_cached_zone()
1182*83ee113eSDavid van Moolenbroek 	 */
1183*83ee113eSDavid van Moolenbroek 
1184*83ee113eSDavid van Moolenbroek 	/* Allocate the control block for this request */
1185*83ee113eSDavid van Moolenbroek 	ns_cb = dmalloc(sizeof(*ns_cb), MDL);
1186*83ee113eSDavid van Moolenbroek 	if (ns_cb == NULL) {
1187*83ee113eSDavid van Moolenbroek 		log_error("find_zone_start: unable to allocate cb");
1188*83ee113eSDavid van Moolenbroek 		return(ISC_R_FAILURE);
1189*83ee113eSDavid van Moolenbroek 	}
1190*83ee113eSDavid van Moolenbroek 	ns_cb->rdtype = dns_rdatatype_a;
1191*83ee113eSDavid van Moolenbroek 
1192*83ee113eSDavid van Moolenbroek 	/* Copy the data string so the NS lookup is independent of the DDNS */
1193*83ee113eSDavid van Moolenbroek 	if (direction == FIND_FORWARD) {
1194*83ee113eSDavid van Moolenbroek 		data_string_copy(&ns_cb->oname,  &ddns_cb->fwd_name, MDL);
1195*83ee113eSDavid van Moolenbroek 	} else {
1196*83ee113eSDavid van Moolenbroek 		data_string_copy(&ns_cb->oname,  &ddns_cb->rev_name, MDL);
1197*83ee113eSDavid van Moolenbroek 	}
1198*83ee113eSDavid van Moolenbroek 	ns_cb->zname = (char *)ns_cb->oname.data;
1199*83ee113eSDavid van Moolenbroek 
1200*83ee113eSDavid van Moolenbroek 	/*
1201*83ee113eSDavid van Moolenbroek 	 * Check the dns_outstanding_ns queue to see if we are
1202*83ee113eSDavid van Moolenbroek 	 * already processing something that would cover this name
1203*83ee113eSDavid van Moolenbroek 	 */
1204*83ee113eSDavid van Moolenbroek 	if (find_in_ns_queue(ns_cb) == ISC_R_SUCCESS) {
1205*83ee113eSDavid van Moolenbroek 		data_string_forget(&ns_cb->oname, MDL);
1206*83ee113eSDavid van Moolenbroek 		dfree(ns_cb, MDL);
1207*83ee113eSDavid van Moolenbroek 		return (ISC_R_SUCCESS);
1208*83ee113eSDavid van Moolenbroek 	}
1209*83ee113eSDavid van Moolenbroek 
1210*83ee113eSDavid van Moolenbroek 	/* Create a DNS version of the zone name and call the
1211*83ee113eSDavid van Moolenbroek 	 * resolver code */
1212*83ee113eSDavid van Moolenbroek 	if (((status = dhcp_isc_name((unsigned char *)ns_cb->zname,
1213*83ee113eSDavid van Moolenbroek 				     &zname0, &zname))
1214*83ee113eSDavid van Moolenbroek 	     != ISC_R_SUCCESS) ||
1215*83ee113eSDavid van Moolenbroek 	    ((status = zone_resolve(dhcp_gbl_ctx.dnsclient,
1216*83ee113eSDavid van Moolenbroek 				    zname, dns_rdataclass_in,
1217*83ee113eSDavid van Moolenbroek 				    dns_rdatatype_ns,
1218*83ee113eSDavid van Moolenbroek 				    DNS_CLIENTRESOPT_NODNSSEC,
1219*83ee113eSDavid van Moolenbroek 				    dhcp_gbl_ctx.task,
1220*83ee113eSDavid van Moolenbroek 				    find_zone_ns,
1221*83ee113eSDavid van Moolenbroek 				    (void *)ns_cb,
1222*83ee113eSDavid van Moolenbroek 				    &ns_cb->transaction))
1223*83ee113eSDavid van Moolenbroek 	     != ISC_R_SUCCESS)) {
1224*83ee113eSDavid van Moolenbroek 		log_error("find_zone_start: Unable to build "
1225*83ee113eSDavid van Moolenbroek 			  "name or start resolve: %s %s",
1226*83ee113eSDavid van Moolenbroek 			  ns_cb->zname,
1227*83ee113eSDavid van Moolenbroek 			  isc_result_totext(status));
1228*83ee113eSDavid van Moolenbroek 
1229*83ee113eSDavid van Moolenbroek 		/* We failed to start the process, clean up */
1230*83ee113eSDavid van Moolenbroek 		data_string_forget(&ns_cb->oname, MDL);
1231*83ee113eSDavid van Moolenbroek 		dfree(ns_cb, MDL);
1232*83ee113eSDavid van Moolenbroek 	} else {
1233*83ee113eSDavid van Moolenbroek 		/* We started the process, attach the control block
1234*83ee113eSDavid van Moolenbroek 		 * to the queue */
1235*83ee113eSDavid van Moolenbroek 		add_to_ns_queue(ns_cb);
1236*83ee113eSDavid van Moolenbroek 	}
1237*83ee113eSDavid van Moolenbroek 
1238*83ee113eSDavid van Moolenbroek 	return (status);
1239*83ee113eSDavid van Moolenbroek }
1240*83ee113eSDavid van Moolenbroek #endif
1241*83ee113eSDavid van Moolenbroek 
1242*83ee113eSDavid van Moolenbroek isc_result_t
find_cached_zone(dhcp_ddns_cb_t * ddns_cb,int direction)1243*83ee113eSDavid van Moolenbroek find_cached_zone(dhcp_ddns_cb_t *ddns_cb, int direction)
1244*83ee113eSDavid van Moolenbroek {
1245*83ee113eSDavid van Moolenbroek 	isc_result_t status = ISC_R_NOTFOUND;
1246*83ee113eSDavid van Moolenbroek 	const char *np;
1247*83ee113eSDavid van Moolenbroek 	struct dns_zone *zone = NULL;
1248*83ee113eSDavid van Moolenbroek 	struct data_string nsaddrs;
1249*83ee113eSDavid van Moolenbroek 	struct in_addr zone_addr;
1250*83ee113eSDavid van Moolenbroek 	struct in6_addr zone_addr6;
1251*83ee113eSDavid van Moolenbroek 	int ix;
1252*83ee113eSDavid van Moolenbroek 
1253*83ee113eSDavid van Moolenbroek 	if (direction == FIND_FORWARD) {
1254*83ee113eSDavid van Moolenbroek 		np = (const char *)ddns_cb->fwd_name.data;
1255*83ee113eSDavid van Moolenbroek 	} else {
1256*83ee113eSDavid van Moolenbroek 		np = (const char *)ddns_cb->rev_name.data;
1257*83ee113eSDavid van Moolenbroek 	}
1258*83ee113eSDavid van Moolenbroek 
1259*83ee113eSDavid van Moolenbroek 	/* We can't look up a null zone. */
1260*83ee113eSDavid van Moolenbroek 	if ((np == NULL) || (*np == '\0')) {
1261*83ee113eSDavid van Moolenbroek 		return (DHCP_R_INVALIDARG);
1262*83ee113eSDavid van Moolenbroek 	}
1263*83ee113eSDavid van Moolenbroek 
1264*83ee113eSDavid van Moolenbroek 	/*
1265*83ee113eSDavid van Moolenbroek 	 * For each subzone, try to find a cached zone.
1266*83ee113eSDavid van Moolenbroek 	 */
1267*83ee113eSDavid van Moolenbroek 	for (;;) {
1268*83ee113eSDavid van Moolenbroek 		status = dns_zone_lookup(&zone, np);
1269*83ee113eSDavid van Moolenbroek 		if (status == ISC_R_SUCCESS)
1270*83ee113eSDavid van Moolenbroek 			break;
1271*83ee113eSDavid van Moolenbroek 
1272*83ee113eSDavid van Moolenbroek 		np = strchr(np, '.');
1273*83ee113eSDavid van Moolenbroek 		if (np == NULL)
1274*83ee113eSDavid van Moolenbroek 			break;
1275*83ee113eSDavid van Moolenbroek 		np++;
1276*83ee113eSDavid van Moolenbroek 	}
1277*83ee113eSDavid van Moolenbroek 
1278*83ee113eSDavid van Moolenbroek 	if (status != ISC_R_SUCCESS)
1279*83ee113eSDavid van Moolenbroek 		return (status);
1280*83ee113eSDavid van Moolenbroek 
1281*83ee113eSDavid van Moolenbroek 	/* Make sure the zone is valid, we've already gotten
1282*83ee113eSDavid van Moolenbroek 	 * rid of expired dynamic zones.  Check to see if
1283*83ee113eSDavid van Moolenbroek 	 * we repudiated this zone.  If so give up.
1284*83ee113eSDavid van Moolenbroek 	 */
1285*83ee113eSDavid van Moolenbroek 	if ((zone->flags & DNS_ZONE_INACTIVE) != 0) {
1286*83ee113eSDavid van Moolenbroek 		dns_zone_dereference(&zone, MDL);
1287*83ee113eSDavid van Moolenbroek 		return (ISC_R_FAILURE);
1288*83ee113eSDavid van Moolenbroek 	}
1289*83ee113eSDavid van Moolenbroek 
1290*83ee113eSDavid van Moolenbroek 	/* Make sure the zone name will fit. */
1291*83ee113eSDavid van Moolenbroek 	if (strlen(zone->name) > sizeof(ddns_cb->zone_name)) {
1292*83ee113eSDavid van Moolenbroek 		dns_zone_dereference(&zone, MDL);
1293*83ee113eSDavid van Moolenbroek 		return (ISC_R_NOSPACE);
1294*83ee113eSDavid van Moolenbroek 	}
1295*83ee113eSDavid van Moolenbroek 	strcpy((char *)&ddns_cb->zone_name[0], zone->name);
1296*83ee113eSDavid van Moolenbroek 
1297*83ee113eSDavid van Moolenbroek 	memset (&nsaddrs, 0, sizeof nsaddrs);
1298*83ee113eSDavid van Moolenbroek 	ix = 0;
1299*83ee113eSDavid van Moolenbroek 
1300*83ee113eSDavid van Moolenbroek 	if (zone->primary) {
1301*83ee113eSDavid van Moolenbroek 		if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL,
1302*83ee113eSDavid van Moolenbroek 					  NULL, NULL, &global_scope,
1303*83ee113eSDavid van Moolenbroek 					  zone->primary, MDL)) {
1304*83ee113eSDavid van Moolenbroek 			int ip = 0;
1305*83ee113eSDavid van Moolenbroek 			while (ix < DHCP_MAXNS) {
1306*83ee113eSDavid van Moolenbroek 				if (ip + 4 > nsaddrs.len)
1307*83ee113eSDavid van Moolenbroek 					break;
1308*83ee113eSDavid van Moolenbroek 				memcpy(&zone_addr, &nsaddrs.data[ip], 4);
1309*83ee113eSDavid van Moolenbroek 				isc_sockaddr_fromin(&ddns_cb->zone_addrs[ix],
1310*83ee113eSDavid van Moolenbroek 						    &zone_addr,
1311*83ee113eSDavid van Moolenbroek 						    NS_DEFAULTPORT);
1312*83ee113eSDavid van Moolenbroek 				ISC_LIST_APPEND(ddns_cb->zone_server_list,
1313*83ee113eSDavid van Moolenbroek 						&ddns_cb->zone_addrs[ix],
1314*83ee113eSDavid van Moolenbroek 						link);
1315*83ee113eSDavid van Moolenbroek 				ip += 4;
1316*83ee113eSDavid van Moolenbroek 				ix++;
1317*83ee113eSDavid van Moolenbroek 			}
1318*83ee113eSDavid van Moolenbroek 			data_string_forget(&nsaddrs, MDL);
1319*83ee113eSDavid van Moolenbroek 		}
1320*83ee113eSDavid van Moolenbroek 	}
1321*83ee113eSDavid van Moolenbroek 
1322*83ee113eSDavid van Moolenbroek 	if (zone->primary6) {
1323*83ee113eSDavid van Moolenbroek 		if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL,
1324*83ee113eSDavid van Moolenbroek 					  NULL, NULL, &global_scope,
1325*83ee113eSDavid van Moolenbroek 					  zone->primary6, MDL)) {
1326*83ee113eSDavid van Moolenbroek 			int ip = 0;
1327*83ee113eSDavid van Moolenbroek 			while (ix < DHCP_MAXNS) {
1328*83ee113eSDavid van Moolenbroek 				if (ip + 16 > nsaddrs.len)
1329*83ee113eSDavid van Moolenbroek 					break;
1330*83ee113eSDavid van Moolenbroek 				memcpy(&zone_addr6, &nsaddrs.data[ip], 16);
1331*83ee113eSDavid van Moolenbroek 				isc_sockaddr_fromin6(&ddns_cb->zone_addrs[ix],
1332*83ee113eSDavid van Moolenbroek 						    &zone_addr6,
1333*83ee113eSDavid van Moolenbroek 						    NS_DEFAULTPORT);
1334*83ee113eSDavid van Moolenbroek 				ISC_LIST_APPEND(ddns_cb->zone_server_list,
1335*83ee113eSDavid van Moolenbroek 						&ddns_cb->zone_addrs[ix],
1336*83ee113eSDavid van Moolenbroek 						link);
1337*83ee113eSDavid van Moolenbroek 				ip += 16;
1338*83ee113eSDavid van Moolenbroek 				ix++;
1339*83ee113eSDavid van Moolenbroek 			}
1340*83ee113eSDavid van Moolenbroek 			data_string_forget(&nsaddrs, MDL);
1341*83ee113eSDavid van Moolenbroek 		}
1342*83ee113eSDavid van Moolenbroek 	}
1343*83ee113eSDavid van Moolenbroek 
1344*83ee113eSDavid van Moolenbroek 	if (zone->secondary) {
1345*83ee113eSDavid van Moolenbroek 		if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL,
1346*83ee113eSDavid van Moolenbroek 					  NULL, NULL, &global_scope,
1347*83ee113eSDavid van Moolenbroek 					  zone->secondary, MDL)) {
1348*83ee113eSDavid van Moolenbroek 			int ip = 0;
1349*83ee113eSDavid van Moolenbroek 			while (ix < DHCP_MAXNS) {
1350*83ee113eSDavid van Moolenbroek 				if (ip + 4 > nsaddrs.len)
1351*83ee113eSDavid van Moolenbroek 					break;
1352*83ee113eSDavid van Moolenbroek 				memcpy(&zone_addr, &nsaddrs.data[ip], 4);
1353*83ee113eSDavid van Moolenbroek 				isc_sockaddr_fromin(&ddns_cb->zone_addrs[ix],
1354*83ee113eSDavid van Moolenbroek 						    &zone_addr,
1355*83ee113eSDavid van Moolenbroek 						    NS_DEFAULTPORT);
1356*83ee113eSDavid van Moolenbroek 				ISC_LIST_APPEND(ddns_cb->zone_server_list,
1357*83ee113eSDavid van Moolenbroek 						&ddns_cb->zone_addrs[ix],
1358*83ee113eSDavid van Moolenbroek 						link);
1359*83ee113eSDavid van Moolenbroek 				ip += 4;
1360*83ee113eSDavid van Moolenbroek 				ix++;
1361*83ee113eSDavid van Moolenbroek 			}
1362*83ee113eSDavid van Moolenbroek 			data_string_forget (&nsaddrs, MDL);
1363*83ee113eSDavid van Moolenbroek 		}
1364*83ee113eSDavid van Moolenbroek 	}
1365*83ee113eSDavid van Moolenbroek 
1366*83ee113eSDavid van Moolenbroek 	if (zone->secondary6) {
1367*83ee113eSDavid van Moolenbroek 		if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL,
1368*83ee113eSDavid van Moolenbroek 					  NULL, NULL, &global_scope,
1369*83ee113eSDavid van Moolenbroek 					  zone->secondary6, MDL)) {
1370*83ee113eSDavid van Moolenbroek 			int ip = 0;
1371*83ee113eSDavid van Moolenbroek 			while (ix < DHCP_MAXNS) {
1372*83ee113eSDavid van Moolenbroek 				if (ip + 16 > nsaddrs.len)
1373*83ee113eSDavid van Moolenbroek 					break;
1374*83ee113eSDavid van Moolenbroek 				memcpy(&zone_addr6, &nsaddrs.data[ip], 16);
1375*83ee113eSDavid van Moolenbroek 				isc_sockaddr_fromin6(&ddns_cb->zone_addrs[ix],
1376*83ee113eSDavid van Moolenbroek 						    &zone_addr6,
1377*83ee113eSDavid van Moolenbroek 						    NS_DEFAULTPORT);
1378*83ee113eSDavid van Moolenbroek 				ISC_LIST_APPEND(ddns_cb->zone_server_list,
1379*83ee113eSDavid van Moolenbroek 						&ddns_cb->zone_addrs[ix],
1380*83ee113eSDavid van Moolenbroek 						link);
1381*83ee113eSDavid van Moolenbroek 				ip += 16;
1382*83ee113eSDavid van Moolenbroek 				ix++;
1383*83ee113eSDavid van Moolenbroek 			}
1384*83ee113eSDavid van Moolenbroek 			data_string_forget (&nsaddrs, MDL);
1385*83ee113eSDavid van Moolenbroek 		}
1386*83ee113eSDavid van Moolenbroek 	}
1387*83ee113eSDavid van Moolenbroek 
1388*83ee113eSDavid van Moolenbroek 	dns_zone_reference(&ddns_cb->zone, zone, MDL);
1389*83ee113eSDavid van Moolenbroek 	dns_zone_dereference (&zone, MDL);
1390*83ee113eSDavid van Moolenbroek 	return ISC_R_SUCCESS;
1391*83ee113eSDavid van Moolenbroek }
1392*83ee113eSDavid van Moolenbroek 
forget_zone(struct dns_zone ** zone)1393*83ee113eSDavid van Moolenbroek void forget_zone (struct dns_zone **zone)
1394*83ee113eSDavid van Moolenbroek {
1395*83ee113eSDavid van Moolenbroek 	dns_zone_dereference (zone, MDL);
1396*83ee113eSDavid van Moolenbroek }
1397*83ee113eSDavid van Moolenbroek 
repudiate_zone(struct dns_zone ** zone)1398*83ee113eSDavid van Moolenbroek void repudiate_zone (struct dns_zone **zone)
1399*83ee113eSDavid van Moolenbroek {
1400*83ee113eSDavid van Moolenbroek 	/* verify that we have a pointer at least */
1401*83ee113eSDavid van Moolenbroek 	if ((zone == NULL) || (*zone == NULL)) {
1402*83ee113eSDavid van Moolenbroek 		log_info("Null argument to repudiate zone");
1403*83ee113eSDavid van Moolenbroek 		return;
1404*83ee113eSDavid van Moolenbroek 	}
1405*83ee113eSDavid van Moolenbroek 
1406*83ee113eSDavid van Moolenbroek 	(*zone)->flags |= DNS_ZONE_INACTIVE;
1407*83ee113eSDavid van Moolenbroek 	dns_zone_dereference(zone, MDL);
1408*83ee113eSDavid van Moolenbroek }
1409*83ee113eSDavid van Moolenbroek 
1410*83ee113eSDavid van Moolenbroek #if defined (DNS_ZONE_LOOKUP)
cache_found_zone(dhcp_ddns_ns_t * ns_cb)1411*83ee113eSDavid van Moolenbroek void cache_found_zone(dhcp_ddns_ns_t *ns_cb)
1412*83ee113eSDavid van Moolenbroek {
1413*83ee113eSDavid van Moolenbroek 	struct dns_zone *zone = NULL;
1414*83ee113eSDavid van Moolenbroek 	int len, remove_zone = 0;
1415*83ee113eSDavid van Moolenbroek 
1416*83ee113eSDavid van Moolenbroek 	/* See if there's already such a zone. */
1417*83ee113eSDavid van Moolenbroek 	if (dns_zone_lookup(&zone, ns_cb->zname) == ISC_R_SUCCESS) {
1418*83ee113eSDavid van Moolenbroek 		/* If it's not a dynamic zone, leave it alone. */
1419*83ee113eSDavid van Moolenbroek 		if (zone->timeout == 0)
1420*83ee113eSDavid van Moolenbroek 			return;
1421*83ee113eSDavid van Moolenbroek 
1422*83ee113eSDavid van Moolenbroek 		/* Remove any old addresses in case they've changed */
1423*83ee113eSDavid van Moolenbroek 		if (zone->primary)
1424*83ee113eSDavid van Moolenbroek 			option_cache_dereference(&zone->primary, MDL);
1425*83ee113eSDavid van Moolenbroek 		if (zone->primary6)
1426*83ee113eSDavid van Moolenbroek 			option_cache_dereference(&zone->primary6, MDL);
1427*83ee113eSDavid van Moolenbroek 
1428*83ee113eSDavid van Moolenbroek 		/* Set the flag to remove the zone from the hash if
1429*83ee113eSDavid van Moolenbroek 		   we have problems */
1430*83ee113eSDavid van Moolenbroek 		remove_zone = 1;
1431*83ee113eSDavid van Moolenbroek 	} else if (dns_zone_allocate(&zone, MDL) == 0) {
1432*83ee113eSDavid van Moolenbroek 		return;
1433*83ee113eSDavid van Moolenbroek 	} else {
1434*83ee113eSDavid van Moolenbroek 		/* We've just allocated the zone, now we need
1435*83ee113eSDavid van Moolenbroek 		 * to allocate space for the name and addresses
1436*83ee113eSDavid van Moolenbroek 		 */
1437*83ee113eSDavid van Moolenbroek 
1438*83ee113eSDavid van Moolenbroek 		/* allocate space for the name */
1439*83ee113eSDavid van Moolenbroek 		len = strlen(ns_cb->zname);
1440*83ee113eSDavid van Moolenbroek 		zone->name = dmalloc(len + 2, MDL);
1441*83ee113eSDavid van Moolenbroek 		if (zone->name == NULL) {
1442*83ee113eSDavid van Moolenbroek 			goto cleanup;
1443*83ee113eSDavid van Moolenbroek 		}
1444*83ee113eSDavid van Moolenbroek 
1445*83ee113eSDavid van Moolenbroek 		/* Copy the name and add a trailing '.' if necessary */
1446*83ee113eSDavid van Moolenbroek 		strcpy(zone->name, ns_cb->zname);
1447*83ee113eSDavid van Moolenbroek 		if (zone->name[len-1] != '.') {
1448*83ee113eSDavid van Moolenbroek 			zone->name[len] = '.';
1449*83ee113eSDavid van Moolenbroek 			zone->name[len+1] = 0;
1450*83ee113eSDavid van Moolenbroek 		}
1451*83ee113eSDavid van Moolenbroek 	}
1452*83ee113eSDavid van Moolenbroek 
1453*83ee113eSDavid van Moolenbroek 	zone->timeout = cur_time + ns_cb->ttl;
1454*83ee113eSDavid van Moolenbroek 
1455*83ee113eSDavid van Moolenbroek 	if (ns_cb->num_addrs != 0) {
1456*83ee113eSDavid van Moolenbroek 		len = ns_cb->num_addrs * sizeof(struct in_addr);
1457*83ee113eSDavid van Moolenbroek 		if ((!option_cache_allocate(&zone->primary, MDL)) ||
1458*83ee113eSDavid van Moolenbroek 		    (!buffer_allocate(&zone->primary->data.buffer,
1459*83ee113eSDavid van Moolenbroek 				      len, MDL))) {
1460*83ee113eSDavid van Moolenbroek 			if (remove_zone == 1)
1461*83ee113eSDavid van Moolenbroek 				remove_dns_zone(zone);
1462*83ee113eSDavid van Moolenbroek 			goto cleanup;
1463*83ee113eSDavid van Moolenbroek 		}
1464*83ee113eSDavid van Moolenbroek 		memcpy(zone->primary->data.buffer->data, ns_cb->addrs, len);
1465*83ee113eSDavid van Moolenbroek 		zone->primary->data.data =
1466*83ee113eSDavid van Moolenbroek 			&zone->primary->data.buffer->data[0];
1467*83ee113eSDavid van Moolenbroek 		zone->primary->data.len = len;
1468*83ee113eSDavid van Moolenbroek 	}
1469*83ee113eSDavid van Moolenbroek 	if (ns_cb->num_addrs6 != 0) {
1470*83ee113eSDavid van Moolenbroek 		len = ns_cb->num_addrs6 * sizeof(struct in6_addr);
1471*83ee113eSDavid van Moolenbroek 		if ((!option_cache_allocate(&zone->primary6, MDL)) ||
1472*83ee113eSDavid van Moolenbroek 		    (!buffer_allocate(&zone->primary6->data.buffer,
1473*83ee113eSDavid van Moolenbroek 				      len, MDL))) {
1474*83ee113eSDavid van Moolenbroek 			if (remove_zone == 1)
1475*83ee113eSDavid van Moolenbroek 				remove_dns_zone(zone);
1476*83ee113eSDavid van Moolenbroek 			goto cleanup;
1477*83ee113eSDavid van Moolenbroek 		}
1478*83ee113eSDavid van Moolenbroek 		memcpy(zone->primary6->data.buffer->data, ns_cb->addrs6, len);
1479*83ee113eSDavid van Moolenbroek 		zone->primary6->data.data =
1480*83ee113eSDavid van Moolenbroek 			&zone->primary6->data.buffer->data[0];
1481*83ee113eSDavid van Moolenbroek 		zone->primary6->data.len = len;
1482*83ee113eSDavid van Moolenbroek 	}
1483*83ee113eSDavid van Moolenbroek 
1484*83ee113eSDavid van Moolenbroek 	enter_dns_zone(zone);
1485*83ee113eSDavid van Moolenbroek 
1486*83ee113eSDavid van Moolenbroek  cleanup:
1487*83ee113eSDavid van Moolenbroek 	dns_zone_dereference(&zone, MDL);
1488*83ee113eSDavid van Moolenbroek 	return;
1489*83ee113eSDavid van Moolenbroek }
1490*83ee113eSDavid van Moolenbroek #endif
1491*83ee113eSDavid van Moolenbroek 
1492*83ee113eSDavid van Moolenbroek /*!
1493*83ee113eSDavid van Moolenbroek  * \brief Create an id for a client
1494*83ee113eSDavid van Moolenbroek  *
1495*83ee113eSDavid van Moolenbroek  * This function is used to create an id for a client to use with DDNS
1496*83ee113eSDavid van Moolenbroek  * This version of the function is for the standard style, RFC 4701
1497*83ee113eSDavid van Moolenbroek  *
1498*83ee113eSDavid van Moolenbroek  * This function takes information from the type and data fields and
1499*83ee113eSDavid van Moolenbroek  * mangles it into a dhcid string which it places in ddns_cb.  It also
1500*83ee113eSDavid van Moolenbroek  * sets a field in ddns_cb to specify the class that should be used
1501*83ee113eSDavid van Moolenbroek  * when sending the dhcid, in this case it is a DHCID record so we use
1502*83ee113eSDavid van Moolenbroek  * dns_rdatatype_dhcid
1503*83ee113eSDavid van Moolenbroek  *
1504*83ee113eSDavid van Moolenbroek  * The DHCID we construct is:
1505*83ee113eSDavid van Moolenbroek  *  2 bytes - identifier type (see 4701 and IANA)
1506*83ee113eSDavid van Moolenbroek  *  1 byte  - digest type, currently only SHA256 (1)
1507*83ee113eSDavid van Moolenbroek  *  n bytes - digest, length depends on digest type, currently 32 for
1508*83ee113eSDavid van Moolenbroek  *            SHA256
1509*83ee113eSDavid van Moolenbroek  *
1510*83ee113eSDavid van Moolenbroek  * What we base the digest on is up to the calling code for an id type of
1511*83ee113eSDavid van Moolenbroek  * 0 - 1 octet htype followed by hlen octets of chaddr from v4 client request
1512*83ee113eSDavid van Moolenbroek  * 1 - data octets from a dhcpv4 client's client identifier option
1513*83ee113eSDavid van Moolenbroek  * 2 - the client DUID from a v4 or v6 client's client id option
1514*83ee113eSDavid van Moolenbroek  * This identifier is concatenated with the fqdn and the result is digested.
1515*83ee113eSDavid van Moolenbroek  */
get_std_dhcid(dhcp_ddns_cb_t * ddns_cb,int type,const u_int8_t * identifier,unsigned id_len)1516*83ee113eSDavid van Moolenbroek static int get_std_dhcid(dhcp_ddns_cb_t *ddns_cb,
1517*83ee113eSDavid van Moolenbroek 		  int type,
1518*83ee113eSDavid van Moolenbroek 		  const u_int8_t *identifier,
1519*83ee113eSDavid van Moolenbroek 		  unsigned id_len)
1520*83ee113eSDavid van Moolenbroek {
1521*83ee113eSDavid van Moolenbroek 	struct data_string *id = &ddns_cb->dhcid;
1522*83ee113eSDavid van Moolenbroek 	isc_sha256_t sha256;
1523*83ee113eSDavid van Moolenbroek 	unsigned char buf[ISC_SHA256_DIGESTLENGTH];
1524*83ee113eSDavid van Moolenbroek 	unsigned char fwd_buf[256];
1525*83ee113eSDavid van Moolenbroek 	unsigned fwd_buflen = 0;
1526*83ee113eSDavid van Moolenbroek 
1527*83ee113eSDavid van Moolenbroek 	/* Types can only be 0..(2^16)-1. */
1528*83ee113eSDavid van Moolenbroek 	if (type < 0 || type > 65535)
1529*83ee113eSDavid van Moolenbroek 		return (0);
1530*83ee113eSDavid van Moolenbroek 
1531*83ee113eSDavid van Moolenbroek 	/* We need to convert the fwd name to wire representation */
1532*83ee113eSDavid van Moolenbroek 	if (MRns_name_pton((char *)ddns_cb->fwd_name.data, fwd_buf, 256) == -1)
1533*83ee113eSDavid van Moolenbroek 		return (0);
1534*83ee113eSDavid van Moolenbroek 	while(fwd_buf[fwd_buflen] != 0) {
1535*83ee113eSDavid van Moolenbroek 		fwd_buflen += fwd_buf[fwd_buflen] + 1;
1536*83ee113eSDavid van Moolenbroek 	}
1537*83ee113eSDavid van Moolenbroek 	fwd_buflen++;
1538*83ee113eSDavid van Moolenbroek 
1539*83ee113eSDavid van Moolenbroek 	if (!buffer_allocate(&id->buffer,
1540*83ee113eSDavid van Moolenbroek 			     ISC_SHA256_DIGESTLENGTH + 2 + 1,
1541*83ee113eSDavid van Moolenbroek 			     MDL))
1542*83ee113eSDavid van Moolenbroek 		return (0);
1543*83ee113eSDavid van Moolenbroek 	id->data = id->buffer->data;
1544*83ee113eSDavid van Moolenbroek 
1545*83ee113eSDavid van Moolenbroek 	/* The two first bytes contain the type identifier. */
1546*83ee113eSDavid van Moolenbroek 	putUShort(id->buffer->data, (unsigned)type);
1547*83ee113eSDavid van Moolenbroek 
1548*83ee113eSDavid van Moolenbroek 	/* The next is the digest type, SHA-256 is 1 */
1549*83ee113eSDavid van Moolenbroek 	putUChar(id->buffer->data + 2, 1u);
1550*83ee113eSDavid van Moolenbroek 
1551*83ee113eSDavid van Moolenbroek 	/* Computing the digest */
1552*83ee113eSDavid van Moolenbroek 	isc_sha256_init(&sha256);
1553*83ee113eSDavid van Moolenbroek 	isc_sha256_update(&sha256, identifier, id_len);
1554*83ee113eSDavid van Moolenbroek 	isc_sha256_update(&sha256, fwd_buf, fwd_buflen);
1555*83ee113eSDavid van Moolenbroek 	isc_sha256_final(buf, &sha256);
1556*83ee113eSDavid van Moolenbroek 
1557*83ee113eSDavid van Moolenbroek 	memcpy(id->buffer->data + 3, &buf, ISC_SHA256_DIGESTLENGTH);
1558*83ee113eSDavid van Moolenbroek 
1559*83ee113eSDavid van Moolenbroek 	id->len = ISC_SHA256_DIGESTLENGTH + 2 + 1;
1560*83ee113eSDavid van Moolenbroek 
1561*83ee113eSDavid van Moolenbroek 	return (1);
1562*83ee113eSDavid van Moolenbroek }
1563*83ee113eSDavid van Moolenbroek 
1564*83ee113eSDavid van Moolenbroek /*!
1565*83ee113eSDavid van Moolenbroek  *
1566*83ee113eSDavid van Moolenbroek  * \brief Create an id for a client
1567*83ee113eSDavid van Moolenbroek  *
1568*83ee113eSDavid van Moolenbroek  * This function is used to create an id for a client to use with DDNS
1569*83ee113eSDavid van Moolenbroek  * This version of the function is for the interim style.  It is retained
1570*83ee113eSDavid van Moolenbroek  * to allow users to continue using the interim style but they should
1571*83ee113eSDavid van Moolenbroek  * switch to the standard style (which uses get_std_dhcid) for better
1572*83ee113eSDavid van Moolenbroek  * interoperability.
1573*83ee113eSDavid van Moolenbroek  *
1574*83ee113eSDavid van Moolenbroek  * This function takes information from the type and data fields and
1575*83ee113eSDavid van Moolenbroek  * mangles it into a dhcid string which it places in ddns_cb.  It also
1576*83ee113eSDavid van Moolenbroek  * sets a field in ddns_cb to specify the class that should be used
1577*83ee113eSDavid van Moolenbroek  * when sending the dhcid, in this case it is a txt record so we use
1578*83ee113eSDavid van Moolenbroek  * dns_rdata_type_txt
1579*83ee113eSDavid van Moolenbroek  *
1580*83ee113eSDavid van Moolenbroek  * NOTE WELL: this function has issues with how it calculates the
1581*83ee113eSDavid van Moolenbroek  * dhcid, they can't be changed now as that would break the records
1582*83ee113eSDavid van Moolenbroek  * already in use.
1583*83ee113eSDavid van Moolenbroek  */
1584*83ee113eSDavid van Moolenbroek 
get_int_dhcid(dhcp_ddns_cb_t * ddns_cb,int type,const u_int8_t * data,unsigned len)1585*83ee113eSDavid van Moolenbroek static int get_int_dhcid (dhcp_ddns_cb_t *ddns_cb,
1586*83ee113eSDavid van Moolenbroek 		   int type,
1587*83ee113eSDavid van Moolenbroek 		   const u_int8_t *data,
1588*83ee113eSDavid van Moolenbroek 		   unsigned len)
1589*83ee113eSDavid van Moolenbroek {
1590*83ee113eSDavid van Moolenbroek 	struct data_string *id = &ddns_cb->dhcid;
1591*83ee113eSDavid van Moolenbroek 	unsigned char buf[ISC_MD5_DIGESTLENGTH];
1592*83ee113eSDavid van Moolenbroek 	isc_md5_t md5;
1593*83ee113eSDavid van Moolenbroek 	int i;
1594*83ee113eSDavid van Moolenbroek 
1595*83ee113eSDavid van Moolenbroek 	/* Types can only be 0..(2^16)-1. */
1596*83ee113eSDavid van Moolenbroek 	if (type < 0 || type > 65535)
1597*83ee113eSDavid van Moolenbroek 		return (0);
1598*83ee113eSDavid van Moolenbroek 
1599*83ee113eSDavid van Moolenbroek 	/*
1600*83ee113eSDavid van Moolenbroek 	 * Hexadecimal MD5 digest plus two byte type, NUL,
1601*83ee113eSDavid van Moolenbroek 	 * and one byte for length for dns.
1602*83ee113eSDavid van Moolenbroek 	 */
1603*83ee113eSDavid van Moolenbroek 	if (!buffer_allocate(&id -> buffer,
1604*83ee113eSDavid van Moolenbroek 			     (ISC_MD5_DIGESTLENGTH * 2) + 4, MDL))
1605*83ee113eSDavid van Moolenbroek 		return (0);
1606*83ee113eSDavid van Moolenbroek 	id->data = id->buffer->data;
1607*83ee113eSDavid van Moolenbroek 
1608*83ee113eSDavid van Moolenbroek 	/*
1609*83ee113eSDavid van Moolenbroek 	 * We put the length into the first byte to turn
1610*83ee113eSDavid van Moolenbroek 	 * this into a dns text string.  This avoid needing to
1611*83ee113eSDavid van Moolenbroek 	 * copy the string to add the byte later.
1612*83ee113eSDavid van Moolenbroek 	 */
1613*83ee113eSDavid van Moolenbroek 	id->buffer->data[0] = ISC_MD5_DIGESTLENGTH * 2 + 2;
1614*83ee113eSDavid van Moolenbroek 
1615*83ee113eSDavid van Moolenbroek 	/* Put the type in the next two bytes. */
1616*83ee113eSDavid van Moolenbroek 	id->buffer->data[1] = "0123456789abcdef"[(type >> 4) & 0xf];
1617*83ee113eSDavid van Moolenbroek 	/* This should have been [type & 0xf] but now that
1618*83ee113eSDavid van Moolenbroek 	 * it is in use we need to leave it this way in order
1619*83ee113eSDavid van Moolenbroek 	 * to avoid disturbing customer's lease files
1620*83ee113eSDavid van Moolenbroek 	 */
1621*83ee113eSDavid van Moolenbroek 	id->buffer->data[2] = "0123456789abcdef"[type % 15];
1622*83ee113eSDavid van Moolenbroek 
1623*83ee113eSDavid van Moolenbroek 	/* Mash together an MD5 hash of the identifier. */
1624*83ee113eSDavid van Moolenbroek 	isc_md5_init(&md5);
1625*83ee113eSDavid van Moolenbroek 	isc_md5_update(&md5, data, len);
1626*83ee113eSDavid van Moolenbroek 	isc_md5_final(&md5, buf);
1627*83ee113eSDavid van Moolenbroek 
1628*83ee113eSDavid van Moolenbroek 	/* Convert into ASCII. */
1629*83ee113eSDavid van Moolenbroek 	for (i = 0; i < ISC_MD5_DIGESTLENGTH; i++) {
1630*83ee113eSDavid van Moolenbroek 		id->buffer->data[i * 2 + 3] =
1631*83ee113eSDavid van Moolenbroek 			"0123456789abcdef"[(buf[i] >> 4) & 0xf];
1632*83ee113eSDavid van Moolenbroek 		id->buffer->data[i * 2 + 4] =
1633*83ee113eSDavid van Moolenbroek 			"0123456789abcdef"[buf[i] & 0xf];
1634*83ee113eSDavid van Moolenbroek 	}
1635*83ee113eSDavid van Moolenbroek 
1636*83ee113eSDavid van Moolenbroek 	id->len = ISC_MD5_DIGESTLENGTH * 2 + 3;
1637*83ee113eSDavid van Moolenbroek 	id->buffer->data[id->len] = 0;
1638*83ee113eSDavid van Moolenbroek 	id->terminated = 1;
1639*83ee113eSDavid van Moolenbroek 
1640*83ee113eSDavid van Moolenbroek 	return (1);
1641*83ee113eSDavid van Moolenbroek }
1642*83ee113eSDavid van Moolenbroek 
get_dhcid(dhcp_ddns_cb_t * ddns_cb,int type,const u_int8_t * identifier,unsigned id_len)1643*83ee113eSDavid van Moolenbroek int get_dhcid(dhcp_ddns_cb_t *ddns_cb,
1644*83ee113eSDavid van Moolenbroek 	      int type,
1645*83ee113eSDavid van Moolenbroek 	      const u_int8_t *identifier,
1646*83ee113eSDavid van Moolenbroek 	      unsigned id_len)
1647*83ee113eSDavid van Moolenbroek {
1648*83ee113eSDavid van Moolenbroek 	if (ddns_cb->dhcid_class == dns_rdatatype_dhcid)
1649*83ee113eSDavid van Moolenbroek 		return get_std_dhcid(ddns_cb, type, identifier, id_len);
1650*83ee113eSDavid van Moolenbroek 	else
1651*83ee113eSDavid van Moolenbroek 		return get_int_dhcid(ddns_cb, type, identifier, id_len);
1652*83ee113eSDavid van Moolenbroek }
1653*83ee113eSDavid van Moolenbroek 
1654*83ee113eSDavid van Moolenbroek /*
1655*83ee113eSDavid van Moolenbroek  * The dhcid (text version) that we pass to DNS includes a length byte
1656*83ee113eSDavid van Moolenbroek  * at the start but the text we store in the lease doesn't include the
1657*83ee113eSDavid van Moolenbroek  * length byte.  The following routines are to convert between the two
1658*83ee113eSDavid van Moolenbroek  * styles.
1659*83ee113eSDavid van Moolenbroek  *
1660*83ee113eSDavid van Moolenbroek  * When converting from a dhcid to a leaseid we reuse the buffer and
1661*83ee113eSDavid van Moolenbroek  * simply adjust the data pointer and length fields in the data string.
1662*83ee113eSDavid van Moolenbroek  * This avoids any prolems with allocating space.
1663*83ee113eSDavid van Moolenbroek  */
1664*83ee113eSDavid van Moolenbroek 
1665*83ee113eSDavid van Moolenbroek void
dhcid_tolease(struct data_string * dhcid,struct data_string * leaseid)1666*83ee113eSDavid van Moolenbroek dhcid_tolease(struct data_string *dhcid,
1667*83ee113eSDavid van Moolenbroek 	      struct data_string *leaseid)
1668*83ee113eSDavid van Moolenbroek {
1669*83ee113eSDavid van Moolenbroek 	/* copy the data string then update the fields */
1670*83ee113eSDavid van Moolenbroek 	data_string_copy(leaseid, dhcid, MDL);
1671*83ee113eSDavid van Moolenbroek 	leaseid->data++;
1672*83ee113eSDavid van Moolenbroek 	leaseid->len--;
1673*83ee113eSDavid van Moolenbroek }
1674*83ee113eSDavid van Moolenbroek 
1675*83ee113eSDavid van Moolenbroek isc_result_t
dhcid_fromlease(struct data_string * dhcid,struct data_string * leaseid)1676*83ee113eSDavid van Moolenbroek dhcid_fromlease(struct data_string *dhcid,
1677*83ee113eSDavid van Moolenbroek 		struct data_string *leaseid)
1678*83ee113eSDavid van Moolenbroek {
1679*83ee113eSDavid van Moolenbroek 	if (!buffer_allocate(&dhcid->buffer, leaseid->len + 2, MDL)) {
1680*83ee113eSDavid van Moolenbroek 		return(ISC_R_FAILURE);
1681*83ee113eSDavid van Moolenbroek 	}
1682*83ee113eSDavid van Moolenbroek 
1683*83ee113eSDavid van Moolenbroek 	dhcid->data = dhcid->buffer->data;
1684*83ee113eSDavid van Moolenbroek 
1685*83ee113eSDavid van Moolenbroek 	dhcid->buffer->data[0] = leaseid->len;
1686*83ee113eSDavid van Moolenbroek 	memcpy(dhcid->buffer->data + 1, leaseid->data, leaseid->len);
1687*83ee113eSDavid van Moolenbroek 	dhcid->len = leaseid->len + 1;
1688*83ee113eSDavid van Moolenbroek 	if (leaseid->terminated == 1) {
1689*83ee113eSDavid van Moolenbroek 		dhcid->buffer->data[dhcid->len] = 0;
1690*83ee113eSDavid van Moolenbroek 		dhcid->terminated = 1;
1691*83ee113eSDavid van Moolenbroek 	}
1692*83ee113eSDavid van Moolenbroek 
1693*83ee113eSDavid van Moolenbroek 	return(ISC_R_SUCCESS);
1694*83ee113eSDavid van Moolenbroek }
1695*83ee113eSDavid van Moolenbroek 
1696*83ee113eSDavid van Moolenbroek /*
1697*83ee113eSDavid van Moolenbroek  * Construct the dataset for this item.
1698*83ee113eSDavid van Moolenbroek  * This is a fairly simple arrangement as the operations we do are simple.
1699*83ee113eSDavid van Moolenbroek  * If there is data we simply have the rdata point to it - the formatting
1700*83ee113eSDavid van Moolenbroek  * must be correct already.  We then link the rdatalist to the rdata and
1701*83ee113eSDavid van Moolenbroek  * create a rdataset from the rdatalist.
1702*83ee113eSDavid van Moolenbroek  */
1703*83ee113eSDavid van Moolenbroek 
1704*83ee113eSDavid van Moolenbroek static isc_result_t
make_dns_dataset(dns_rdataclass_t dataclass,dns_rdatatype_t datatype,dhcp_ddns_data_t * dataspace,unsigned char * data,int datalen,int ttl)1705*83ee113eSDavid van Moolenbroek make_dns_dataset(dns_rdataclass_t  dataclass,
1706*83ee113eSDavid van Moolenbroek 		 dns_rdatatype_t   datatype,
1707*83ee113eSDavid van Moolenbroek 		 dhcp_ddns_data_t *dataspace,
1708*83ee113eSDavid van Moolenbroek 		 unsigned char    *data,
1709*83ee113eSDavid van Moolenbroek 		 int               datalen,
1710*83ee113eSDavid van Moolenbroek 		 int               ttl)
1711*83ee113eSDavid van Moolenbroek {
1712*83ee113eSDavid van Moolenbroek 	dns_rdata_t *rdata = &dataspace->rdata;
1713*83ee113eSDavid van Moolenbroek 	dns_rdatalist_t *rdatalist = &dataspace->rdatalist;
1714*83ee113eSDavid van Moolenbroek 	dns_rdataset_t *rdataset = &dataspace->rdataset;
1715*83ee113eSDavid van Moolenbroek 
1716*83ee113eSDavid van Moolenbroek 	isc_region_t region;
1717*83ee113eSDavid van Moolenbroek 
1718*83ee113eSDavid van Moolenbroek 	/* set up the rdata */
1719*83ee113eSDavid van Moolenbroek 	dns_rdata_init(rdata);
1720*83ee113eSDavid van Moolenbroek 
1721*83ee113eSDavid van Moolenbroek 	if (data == NULL) {
1722*83ee113eSDavid van Moolenbroek 		/* No data, set up the rdata fields we care about */
1723*83ee113eSDavid van Moolenbroek 		rdata->flags = DNS_RDATA_UPDATE;
1724*83ee113eSDavid van Moolenbroek 		rdata->type = datatype;
1725*83ee113eSDavid van Moolenbroek 		rdata->rdclass = dataclass;
1726*83ee113eSDavid van Moolenbroek 	} else {
1727*83ee113eSDavid van Moolenbroek 		switch(datatype) {
1728*83ee113eSDavid van Moolenbroek 		case dns_rdatatype_a:
1729*83ee113eSDavid van Moolenbroek 		case dns_rdatatype_aaaa:
1730*83ee113eSDavid van Moolenbroek 		case dns_rdatatype_txt:
1731*83ee113eSDavid van Moolenbroek 		case dns_rdatatype_dhcid:
1732*83ee113eSDavid van Moolenbroek 		case dns_rdatatype_ptr:
1733*83ee113eSDavid van Moolenbroek 			/* The data must be in the right format we simply
1734*83ee113eSDavid van Moolenbroek 			 * need to supply it via the correct structure */
1735*83ee113eSDavid van Moolenbroek 			region.base   = data;
1736*83ee113eSDavid van Moolenbroek 			region.length = datalen;
1737*83ee113eSDavid van Moolenbroek 			dns_rdata_fromregion(rdata, dataclass, datatype,
1738*83ee113eSDavid van Moolenbroek 					     &region);
1739*83ee113eSDavid van Moolenbroek 			break;
1740*83ee113eSDavid van Moolenbroek 		default:
1741*83ee113eSDavid van Moolenbroek 			return(DHCP_R_INVALIDARG);
1742*83ee113eSDavid van Moolenbroek 			break;
1743*83ee113eSDavid van Moolenbroek 		}
1744*83ee113eSDavid van Moolenbroek 	}
1745*83ee113eSDavid van Moolenbroek 
1746*83ee113eSDavid van Moolenbroek 	/* setup the datalist and attach the rdata to it */
1747*83ee113eSDavid van Moolenbroek 	dns_rdatalist_init(rdatalist);
1748*83ee113eSDavid van Moolenbroek 	rdatalist->type = datatype;
1749*83ee113eSDavid van Moolenbroek 	rdatalist->rdclass = dataclass;
1750*83ee113eSDavid van Moolenbroek 	rdatalist->ttl = ttl;
1751*83ee113eSDavid van Moolenbroek 	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1752*83ee113eSDavid van Moolenbroek 
1753*83ee113eSDavid van Moolenbroek 	/* convert the datalist to a dataset */
1754*83ee113eSDavid van Moolenbroek 	dns_rdataset_init(rdataset);
1755*83ee113eSDavid van Moolenbroek 	dns_rdatalist_tordataset(rdatalist, rdataset);
1756*83ee113eSDavid van Moolenbroek 
1757*83ee113eSDavid van Moolenbroek 	return(ISC_R_SUCCESS);
1758*83ee113eSDavid van Moolenbroek }
1759*83ee113eSDavid van Moolenbroek 
1760*83ee113eSDavid van Moolenbroek /*
1761*83ee113eSDavid van Moolenbroek  * When a DHCP client or server intends to update an A RR, it first
1762*83ee113eSDavid van Moolenbroek  * prepares a DNS UPDATE query which includes as a prerequisite the
1763*83ee113eSDavid van Moolenbroek  * assertion that the name does not exist.  The update section of the
1764*83ee113eSDavid van Moolenbroek  * query attempts to add the new name and its IP address mapping (an A
1765*83ee113eSDavid van Moolenbroek  * RR), and the DHCID RR with its unique client-identity.
1766*83ee113eSDavid van Moolenbroek  *   -- "Interaction between DHCP and DNS"
1767*83ee113eSDavid van Moolenbroek  *
1768*83ee113eSDavid van Moolenbroek  * There are two cases, one for the server and one for the client.
1769*83ee113eSDavid van Moolenbroek  *
1770*83ee113eSDavid van Moolenbroek  * For the server the first step will have a request of:
1771*83ee113eSDavid van Moolenbroek  * The name is not in use
1772*83ee113eSDavid van Moolenbroek  * Add an A RR
1773*83ee113eSDavid van Moolenbroek  * Add a DHCID RR
1774*83ee113eSDavid van Moolenbroek  *
1775*83ee113eSDavid van Moolenbroek  * For the client the first step will have a request of:
1776*83ee113eSDavid van Moolenbroek  * The A RR does not exist
1777*83ee113eSDavid van Moolenbroek  * Add an A RR
1778*83ee113eSDavid van Moolenbroek  * Add a DHCID RR
1779*83ee113eSDavid van Moolenbroek  */
1780*83ee113eSDavid van Moolenbroek 
1781*83ee113eSDavid van Moolenbroek static isc_result_t
ddns_modify_fwd_add1(dhcp_ddns_cb_t * ddns_cb,dhcp_ddns_data_t * dataspace,dns_name_t * pname,dns_name_t * uname)1782*83ee113eSDavid van Moolenbroek ddns_modify_fwd_add1(dhcp_ddns_cb_t   *ddns_cb,
1783*83ee113eSDavid van Moolenbroek 		     dhcp_ddns_data_t *dataspace,
1784*83ee113eSDavid van Moolenbroek 		     dns_name_t       *pname,
1785*83ee113eSDavid van Moolenbroek 		     dns_name_t       *uname)
1786*83ee113eSDavid van Moolenbroek {
1787*83ee113eSDavid van Moolenbroek 	isc_result_t result;
1788*83ee113eSDavid van Moolenbroek 
1789*83ee113eSDavid van Moolenbroek 	/* Construct the prerequisite list */
1790*83ee113eSDavid van Moolenbroek 	if ((ddns_cb->flags & DDNS_INCLUDE_RRSET) != 0) {
1791*83ee113eSDavid van Moolenbroek 		/* The A RR shouldn't exist */
1792*83ee113eSDavid van Moolenbroek 		result = make_dns_dataset(dns_rdataclass_none,
1793*83ee113eSDavid van Moolenbroek 					  ddns_cb->address_type,
1794*83ee113eSDavid van Moolenbroek 					  dataspace, NULL, 0, 0);
1795*83ee113eSDavid van Moolenbroek 	} else {
1796*83ee113eSDavid van Moolenbroek 		/* The name is not in use */
1797*83ee113eSDavid van Moolenbroek 		result = make_dns_dataset(dns_rdataclass_none,
1798*83ee113eSDavid van Moolenbroek 					  dns_rdatatype_any,
1799*83ee113eSDavid van Moolenbroek 					  dataspace, NULL, 0, 0);
1800*83ee113eSDavid van Moolenbroek 	}
1801*83ee113eSDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
1802*83ee113eSDavid van Moolenbroek 		return(result);
1803*83ee113eSDavid van Moolenbroek 	}
1804*83ee113eSDavid van Moolenbroek 	ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
1805*83ee113eSDavid van Moolenbroek 	dataspace++;
1806*83ee113eSDavid van Moolenbroek 
1807*83ee113eSDavid van Moolenbroek 	/* Construct the update list */
1808*83ee113eSDavid van Moolenbroek 	/* Add the A RR */
1809*83ee113eSDavid van Moolenbroek 	result = make_dns_dataset(dns_rdataclass_in, ddns_cb->address_type,
1810*83ee113eSDavid van Moolenbroek 				  dataspace,
1811*83ee113eSDavid van Moolenbroek 				  (unsigned char *)ddns_cb->address.iabuf,
1812*83ee113eSDavid van Moolenbroek 				  ddns_cb->address.len, ddns_cb->ttl);
1813*83ee113eSDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
1814*83ee113eSDavid van Moolenbroek 		return(result);
1815*83ee113eSDavid van Moolenbroek 	}
1816*83ee113eSDavid van Moolenbroek 	ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1817*83ee113eSDavid van Moolenbroek 	dataspace++;
1818*83ee113eSDavid van Moolenbroek 
1819*83ee113eSDavid van Moolenbroek 	/* Add the DHCID RR */
1820*83ee113eSDavid van Moolenbroek 	result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class,
1821*83ee113eSDavid van Moolenbroek 				  dataspace,
1822*83ee113eSDavid van Moolenbroek 				  (unsigned char *)ddns_cb->dhcid.data,
1823*83ee113eSDavid van Moolenbroek 				  ddns_cb->dhcid.len, ddns_cb->ttl);
1824*83ee113eSDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
1825*83ee113eSDavid van Moolenbroek 		return(result);
1826*83ee113eSDavid van Moolenbroek 	}
1827*83ee113eSDavid van Moolenbroek 	ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1828*83ee113eSDavid van Moolenbroek 
1829*83ee113eSDavid van Moolenbroek 	return(ISC_R_SUCCESS);
1830*83ee113eSDavid van Moolenbroek }
1831*83ee113eSDavid van Moolenbroek 
1832*83ee113eSDavid van Moolenbroek /*
1833*83ee113eSDavid van Moolenbroek  * If the first update operation fails with YXDOMAIN, the updater can
1834*83ee113eSDavid van Moolenbroek  * conclude that the intended name is in use.  The updater then
1835*83ee113eSDavid van Moolenbroek  * attempts to confirm that the DNS name is not being used by some
1836*83ee113eSDavid van Moolenbroek  * other host. The updater prepares a second UPDATE query in which the
1837*83ee113eSDavid van Moolenbroek  * prerequisite is that the desired name has attached to it a DHCID RR
1838*83ee113eSDavid van Moolenbroek  * whose contents match the client identity.  The update section of
1839*83ee113eSDavid van Moolenbroek  * this query deletes the existing A records on the name, and adds the
1840*83ee113eSDavid van Moolenbroek  * A record that matches the DHCP binding and the DHCID RR with the
1841*83ee113eSDavid van Moolenbroek  * client identity.
1842*83ee113eSDavid van Moolenbroek  *   -- "Interaction between DHCP and DNS"
1843*83ee113eSDavid van Moolenbroek  *
1844*83ee113eSDavid van Moolenbroek  * The message for the second step depends on if we are doing conflict
1845*83ee113eSDavid van Moolenbroek  * resolution.  If we are we include a prerequisite.  If not we delete
1846*83ee113eSDavid van Moolenbroek  * the DHCID in addition to all A rrsets.
1847*83ee113eSDavid van Moolenbroek  *
1848*83ee113eSDavid van Moolenbroek  * Conflict resolution:
1849*83ee113eSDavid van Moolenbroek  * DHCID RR exists, and matches client identity.
1850*83ee113eSDavid van Moolenbroek  * Delete A RRset.
1851*83ee113eSDavid van Moolenbroek  * Add A RR.
1852*83ee113eSDavid van Moolenbroek  *
1853*83ee113eSDavid van Moolenbroek  * Conflict override:
1854*83ee113eSDavid van Moolenbroek  * Delete DHCID RRs.
1855*83ee113eSDavid van Moolenbroek  * Add DHCID RR
1856*83ee113eSDavid van Moolenbroek  * Delete A RRset.
1857*83ee113eSDavid van Moolenbroek  * Add A RR.
1858*83ee113eSDavid van Moolenbroek  */
1859*83ee113eSDavid van Moolenbroek 
1860*83ee113eSDavid van Moolenbroek static isc_result_t
ddns_modify_fwd_add2(dhcp_ddns_cb_t * ddns_cb,dhcp_ddns_data_t * dataspace,dns_name_t * pname,dns_name_t * uname)1861*83ee113eSDavid van Moolenbroek ddns_modify_fwd_add2(dhcp_ddns_cb_t   *ddns_cb,
1862*83ee113eSDavid van Moolenbroek 		     dhcp_ddns_data_t *dataspace,
1863*83ee113eSDavid van Moolenbroek 		     dns_name_t       *pname,
1864*83ee113eSDavid van Moolenbroek 		     dns_name_t       *uname)
1865*83ee113eSDavid van Moolenbroek {
1866*83ee113eSDavid van Moolenbroek 	isc_result_t result = ISC_R_SUCCESS;
1867*83ee113eSDavid van Moolenbroek 
1868*83ee113eSDavid van Moolenbroek 	/*
1869*83ee113eSDavid van Moolenbroek 	 * If we are doing conflict resolution (unset) we use a prereq list.
1870*83ee113eSDavid van Moolenbroek 	 * If not we delete the DHCID in addition to all A rrsets.
1871*83ee113eSDavid van Moolenbroek 	 */
1872*83ee113eSDavid van Moolenbroek 	if ((ddns_cb->flags & DDNS_CONFLICT_OVERRIDE) == 0) {
1873*83ee113eSDavid van Moolenbroek 		/* Construct the prereq list */
1874*83ee113eSDavid van Moolenbroek 		/* The DHCID RR exists and matches the client identity */
1875*83ee113eSDavid van Moolenbroek 		result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class,
1876*83ee113eSDavid van Moolenbroek 					  dataspace,
1877*83ee113eSDavid van Moolenbroek 					  (unsigned char *)ddns_cb->dhcid.data,
1878*83ee113eSDavid van Moolenbroek 					  ddns_cb->dhcid.len, 0);
1879*83ee113eSDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
1880*83ee113eSDavid van Moolenbroek 			return(result);
1881*83ee113eSDavid van Moolenbroek 		}
1882*83ee113eSDavid van Moolenbroek 		ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
1883*83ee113eSDavid van Moolenbroek 		dataspace++;
1884*83ee113eSDavid van Moolenbroek 	} else {
1885*83ee113eSDavid van Moolenbroek 		/* Start constructing the update list.
1886*83ee113eSDavid van Moolenbroek 		 * Conflict detection override: delete DHCID RRs */
1887*83ee113eSDavid van Moolenbroek 		result = make_dns_dataset(dns_rdataclass_any,
1888*83ee113eSDavid van Moolenbroek 					  ddns_cb->dhcid_class,
1889*83ee113eSDavid van Moolenbroek 					  dataspace, NULL, 0, 0);
1890*83ee113eSDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
1891*83ee113eSDavid van Moolenbroek 			return(result);
1892*83ee113eSDavid van Moolenbroek 		}
1893*83ee113eSDavid van Moolenbroek 		ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1894*83ee113eSDavid van Moolenbroek 		dataspace++;
1895*83ee113eSDavid van Moolenbroek 
1896*83ee113eSDavid van Moolenbroek 		/* Add current DHCID RR */
1897*83ee113eSDavid van Moolenbroek 		result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class,
1898*83ee113eSDavid van Moolenbroek 					  dataspace,
1899*83ee113eSDavid van Moolenbroek 					  (unsigned char *)ddns_cb->dhcid.data,
1900*83ee113eSDavid van Moolenbroek 					  ddns_cb->dhcid.len, ddns_cb->ttl);
1901*83ee113eSDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
1902*83ee113eSDavid van Moolenbroek 			return(result);
1903*83ee113eSDavid van Moolenbroek 		}
1904*83ee113eSDavid van Moolenbroek 		ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1905*83ee113eSDavid van Moolenbroek 		dataspace++;
1906*83ee113eSDavid van Moolenbroek 	}
1907*83ee113eSDavid van Moolenbroek 
1908*83ee113eSDavid van Moolenbroek 	/* Start or continue constructing the update list */
1909*83ee113eSDavid van Moolenbroek 	/* Delete the A RRset */
1910*83ee113eSDavid van Moolenbroek 	result = make_dns_dataset(dns_rdataclass_any, ddns_cb->address_type,
1911*83ee113eSDavid van Moolenbroek 				  dataspace, NULL, 0, 0);
1912*83ee113eSDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
1913*83ee113eSDavid van Moolenbroek 		return(result);
1914*83ee113eSDavid van Moolenbroek 	}
1915*83ee113eSDavid van Moolenbroek 	ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1916*83ee113eSDavid van Moolenbroek 	dataspace++;
1917*83ee113eSDavid van Moolenbroek 
1918*83ee113eSDavid van Moolenbroek 	/* Add the A RR */
1919*83ee113eSDavid van Moolenbroek 	result = make_dns_dataset(dns_rdataclass_in, ddns_cb->address_type,
1920*83ee113eSDavid van Moolenbroek 				  dataspace,
1921*83ee113eSDavid van Moolenbroek 				  (unsigned char *)ddns_cb->address.iabuf,
1922*83ee113eSDavid van Moolenbroek 				  ddns_cb->address.len, ddns_cb->ttl);
1923*83ee113eSDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
1924*83ee113eSDavid van Moolenbroek 		return(result);
1925*83ee113eSDavid van Moolenbroek 	}
1926*83ee113eSDavid van Moolenbroek 	ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1927*83ee113eSDavid van Moolenbroek 
1928*83ee113eSDavid van Moolenbroek 	return(ISC_R_SUCCESS);
1929*83ee113eSDavid van Moolenbroek }
1930*83ee113eSDavid van Moolenbroek 
1931*83ee113eSDavid van Moolenbroek /*
1932*83ee113eSDavid van Moolenbroek  * The entity chosen to handle the A record for this client (either the
1933*83ee113eSDavid van Moolenbroek  * client or the server) SHOULD delete the A record that was added when
1934*83ee113eSDavid van Moolenbroek  * the lease was made to the client.
1935*83ee113eSDavid van Moolenbroek  *
1936*83ee113eSDavid van Moolenbroek  * In order to perform this delete, the updater prepares an UPDATE
1937*83ee113eSDavid van Moolenbroek  * query which contains two prerequisites.  The first prerequisite
1938*83ee113eSDavid van Moolenbroek  * asserts that the DHCID RR exists whose data is the client identity
1939*83ee113eSDavid van Moolenbroek  * described in Section 4.3. The second prerequisite asserts that the
1940*83ee113eSDavid van Moolenbroek  * data in the A RR contains the IP address of the lease that has
1941*83ee113eSDavid van Moolenbroek  * expired or been released.
1942*83ee113eSDavid van Moolenbroek  *   -- "Interaction between DHCP and DNS"
1943*83ee113eSDavid van Moolenbroek  *
1944*83ee113eSDavid van Moolenbroek  * RFC 4703 has relaxed the prereqisites to only checking the DHCID RR
1945*83ee113eSDavid van Moolenbroek  * and we have adopted that to minizmie problems due to interruptions
1946*83ee113eSDavid van Moolenbroek  * when doing a deletion.
1947*83ee113eSDavid van Moolenbroek  *
1948*83ee113eSDavid van Moolenbroek  * First try has:
1949*83ee113eSDavid van Moolenbroek  * DHCID RR exists, and matches client identity.
1950*83ee113eSDavid van Moolenbroek  * Delete appropriate A RR.
1951*83ee113eSDavid van Moolenbroek  */
1952*83ee113eSDavid van Moolenbroek 
1953*83ee113eSDavid van Moolenbroek static isc_result_t
ddns_modify_fwd_rem1(dhcp_ddns_cb_t * ddns_cb,dhcp_ddns_data_t * dataspace,dns_name_t * pname,dns_name_t * uname)1954*83ee113eSDavid van Moolenbroek ddns_modify_fwd_rem1(dhcp_ddns_cb_t   *ddns_cb,
1955*83ee113eSDavid van Moolenbroek 		     dhcp_ddns_data_t *dataspace,
1956*83ee113eSDavid van Moolenbroek 		     dns_name_t       *pname,
1957*83ee113eSDavid van Moolenbroek 		     dns_name_t       *uname)
1958*83ee113eSDavid van Moolenbroek {
1959*83ee113eSDavid van Moolenbroek 	isc_result_t result = ISC_R_SUCCESS;
1960*83ee113eSDavid van Moolenbroek 
1961*83ee113eSDavid van Moolenbroek 	/* Consruct the prereq list */
1962*83ee113eSDavid van Moolenbroek 	/* The DHCID RR exists and matches the client identity */
1963*83ee113eSDavid van Moolenbroek 	result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class,
1964*83ee113eSDavid van Moolenbroek 				  dataspace,
1965*83ee113eSDavid van Moolenbroek 				  (unsigned char *)ddns_cb->dhcid.data,
1966*83ee113eSDavid van Moolenbroek 				  ddns_cb->dhcid.len, 0);
1967*83ee113eSDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
1968*83ee113eSDavid van Moolenbroek 		return(result);
1969*83ee113eSDavid van Moolenbroek 	}
1970*83ee113eSDavid van Moolenbroek 	ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
1971*83ee113eSDavid van Moolenbroek 	dataspace++;
1972*83ee113eSDavid van Moolenbroek 
1973*83ee113eSDavid van Moolenbroek 	/* Construct the update list */
1974*83ee113eSDavid van Moolenbroek 	/* Delete A RRset */
1975*83ee113eSDavid van Moolenbroek 	result = make_dns_dataset(dns_rdataclass_none, ddns_cb->address_type,
1976*83ee113eSDavid van Moolenbroek 				  dataspace,
1977*83ee113eSDavid van Moolenbroek 				  (unsigned char *)ddns_cb->address.iabuf,
1978*83ee113eSDavid van Moolenbroek 				  ddns_cb->address.len, 0);
1979*83ee113eSDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
1980*83ee113eSDavid van Moolenbroek 		return(result);
1981*83ee113eSDavid van Moolenbroek 	}
1982*83ee113eSDavid van Moolenbroek 	ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1983*83ee113eSDavid van Moolenbroek 
1984*83ee113eSDavid van Moolenbroek 	return(ISC_R_SUCCESS);
1985*83ee113eSDavid van Moolenbroek }
1986*83ee113eSDavid van Moolenbroek 
1987*83ee113eSDavid van Moolenbroek /*
1988*83ee113eSDavid van Moolenbroek  * If the deletion of the A succeeded, and there are no A or AAAA
1989*83ee113eSDavid van Moolenbroek  * records left for this domain, then we can blow away the DHCID
1990*83ee113eSDavid van Moolenbroek  * record as well.   We can't blow away the DHCID record above
1991*83ee113eSDavid van Moolenbroek  * because it's possible that more than one record has been added
1992*83ee113eSDavid van Moolenbroek  * to this domain name.
1993*83ee113eSDavid van Moolenbroek  *
1994*83ee113eSDavid van Moolenbroek  * Second query has:
1995*83ee113eSDavid van Moolenbroek  * A RR does not exist.
1996*83ee113eSDavid van Moolenbroek  * AAAA RR does not exist.
1997*83ee113eSDavid van Moolenbroek  * Delete appropriate DHCID RR.
1998*83ee113eSDavid van Moolenbroek  */
1999*83ee113eSDavid van Moolenbroek 
2000*83ee113eSDavid van Moolenbroek static isc_result_t
ddns_modify_fwd_rem2(dhcp_ddns_cb_t * ddns_cb,dhcp_ddns_data_t * dataspace,dns_name_t * pname,dns_name_t * uname)2001*83ee113eSDavid van Moolenbroek ddns_modify_fwd_rem2(dhcp_ddns_cb_t   *ddns_cb,
2002*83ee113eSDavid van Moolenbroek 		     dhcp_ddns_data_t *dataspace,
2003*83ee113eSDavid van Moolenbroek 		     dns_name_t       *pname,
2004*83ee113eSDavid van Moolenbroek 		     dns_name_t       *uname)
2005*83ee113eSDavid van Moolenbroek {
2006*83ee113eSDavid van Moolenbroek 	isc_result_t result;
2007*83ee113eSDavid van Moolenbroek 
2008*83ee113eSDavid van Moolenbroek 	/* Construct the prereq list */
2009*83ee113eSDavid van Moolenbroek 	/* The A RR does not exist */
2010*83ee113eSDavid van Moolenbroek 	result = make_dns_dataset(dns_rdataclass_none, dns_rdatatype_a,
2011*83ee113eSDavid van Moolenbroek 				  dataspace, NULL, 0, 0);
2012*83ee113eSDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
2013*83ee113eSDavid van Moolenbroek 		return(result);
2014*83ee113eSDavid van Moolenbroek 	}
2015*83ee113eSDavid van Moolenbroek 	ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
2016*83ee113eSDavid van Moolenbroek 	dataspace++;
2017*83ee113eSDavid van Moolenbroek 
2018*83ee113eSDavid van Moolenbroek 	/* The AAAA RR does not exist */
2019*83ee113eSDavid van Moolenbroek 	result = make_dns_dataset(dns_rdataclass_none, dns_rdatatype_aaaa,
2020*83ee113eSDavid van Moolenbroek 				  dataspace, NULL, 0, 0);
2021*83ee113eSDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
2022*83ee113eSDavid van Moolenbroek 		return(result);
2023*83ee113eSDavid van Moolenbroek 	}
2024*83ee113eSDavid van Moolenbroek 	ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
2025*83ee113eSDavid van Moolenbroek 	dataspace++;
2026*83ee113eSDavid van Moolenbroek 
2027*83ee113eSDavid van Moolenbroek 	/* Construct the update list */
2028*83ee113eSDavid van Moolenbroek 	/* Delete DHCID RR */
2029*83ee113eSDavid van Moolenbroek 	result = make_dns_dataset(dns_rdataclass_none, ddns_cb->dhcid_class,
2030*83ee113eSDavid van Moolenbroek 				  dataspace,
2031*83ee113eSDavid van Moolenbroek 				  (unsigned char *)ddns_cb->dhcid.data,
2032*83ee113eSDavid van Moolenbroek 				  ddns_cb->dhcid.len, 0);
2033*83ee113eSDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
2034*83ee113eSDavid van Moolenbroek 		return(result);
2035*83ee113eSDavid van Moolenbroek 	}
2036*83ee113eSDavid van Moolenbroek 	ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
2037*83ee113eSDavid van Moolenbroek 
2038*83ee113eSDavid van Moolenbroek 	return(ISC_R_SUCCESS);
2039*83ee113eSDavid van Moolenbroek }
2040*83ee113eSDavid van Moolenbroek 
2041*83ee113eSDavid van Moolenbroek /*
2042*83ee113eSDavid van Moolenbroek  * This routine converts from the task action call into something
2043*83ee113eSDavid van Moolenbroek  * easier to work with.  It also handles the common case of a signature
2044*83ee113eSDavid van Moolenbroek  * or zone not being correct.
2045*83ee113eSDavid van Moolenbroek  */
ddns_interlude(isc_task_t * taskp,isc_event_t * eventp)2046*83ee113eSDavid van Moolenbroek void ddns_interlude(isc_task_t  *taskp,
2047*83ee113eSDavid van Moolenbroek 		    isc_event_t *eventp)
2048*83ee113eSDavid van Moolenbroek {
2049*83ee113eSDavid van Moolenbroek 	dhcp_ddns_cb_t *ddns_cb = (dhcp_ddns_cb_t *)eventp->ev_arg;
2050*83ee113eSDavid van Moolenbroek 	dns_clientupdateevent_t *ddns_event = (dns_clientupdateevent_t *)eventp;
2051*83ee113eSDavid van Moolenbroek 	isc_result_t eresult = ddns_event->result;
2052*83ee113eSDavid van Moolenbroek 	isc_result_t result;
2053*83ee113eSDavid van Moolenbroek 
2054*83ee113eSDavid van Moolenbroek 	/* We've extracted the information we want from it, get rid of
2055*83ee113eSDavid van Moolenbroek 	 * the event block.*/
2056*83ee113eSDavid van Moolenbroek 	isc_event_free(&eventp);
2057*83ee113eSDavid van Moolenbroek 
2058*83ee113eSDavid van Moolenbroek #if defined (TRACING)
2059*83ee113eSDavid van Moolenbroek 	if (trace_record()) {
2060*83ee113eSDavid van Moolenbroek 		trace_ddns_input_write(ddns_cb, eresult);
2061*83ee113eSDavid van Moolenbroek 	}
2062*83ee113eSDavid van Moolenbroek #endif
2063*83ee113eSDavid van Moolenbroek 
2064*83ee113eSDavid van Moolenbroek #if defined (DEBUG_DNS_UPDATES)
2065*83ee113eSDavid van Moolenbroek 	print_dns_status(DDNS_PRINT_INBOUND, ddns_cb, eresult);
2066*83ee113eSDavid van Moolenbroek #endif
2067*83ee113eSDavid van Moolenbroek 
2068*83ee113eSDavid van Moolenbroek 	/* This transaction is complete, clear the value */
2069*83ee113eSDavid van Moolenbroek 	dns_client_destroyupdatetrans(&ddns_cb->transaction);
2070*83ee113eSDavid van Moolenbroek 
2071*83ee113eSDavid van Moolenbroek 	/* If we cancelled or tried to cancel the operation we just
2072*83ee113eSDavid van Moolenbroek 	 * need to clean up. */
2073*83ee113eSDavid van Moolenbroek 	if ((eresult == ISC_R_CANCELED) ||
2074*83ee113eSDavid van Moolenbroek 	    ((ddns_cb->flags & DDNS_ABORT) != 0)) {
2075*83ee113eSDavid van Moolenbroek #if defined (DEBUG_DNS_UPDATES)
2076*83ee113eSDavid van Moolenbroek 		log_info("DDNS: completeing transaction cancellation cb=%p, "
2077*83ee113eSDavid van Moolenbroek 			 "flags=%x, %s",
2078*83ee113eSDavid van Moolenbroek 			 ddns_cb, ddns_cb->flags, isc_result_totext(eresult));
2079*83ee113eSDavid van Moolenbroek #endif
2080*83ee113eSDavid van Moolenbroek 		if ((ddns_cb->flags & DDNS_ABORT) == 0) {
2081*83ee113eSDavid van Moolenbroek 			log_info("DDNS: cleaning up lease pointer for a cancel "
2082*83ee113eSDavid van Moolenbroek 				 "cb=%p", ddns_cb);
2083*83ee113eSDavid van Moolenbroek 			/*
2084*83ee113eSDavid van Moolenbroek 			 * We shouldn't actually be able to get here but
2085*83ee113eSDavid van Moolenbroek 			 * we are.  This means we haven't cleaned up
2086*83ee113eSDavid van Moolenbroek 			 * the lease pointer so we need to do that before
2087*83ee113eSDavid van Moolenbroek 			 * freeing the cb.
2088*83ee113eSDavid van Moolenbroek 			 */
2089*83ee113eSDavid van Moolenbroek 			ddns_cb->cur_func(ddns_cb, eresult);
2090*83ee113eSDavid van Moolenbroek 			return;
2091*83ee113eSDavid van Moolenbroek 		}
2092*83ee113eSDavid van Moolenbroek 
2093*83ee113eSDavid van Moolenbroek 		if (ddns_cb->next_op != NULL) {
2094*83ee113eSDavid van Moolenbroek 			/* if necessary cleanup up next op block */
2095*83ee113eSDavid van Moolenbroek 			ddns_cb_free(ddns_cb->next_op, MDL);
2096*83ee113eSDavid van Moolenbroek 		}
2097*83ee113eSDavid van Moolenbroek 		ddns_cb_free(ddns_cb, MDL);
2098*83ee113eSDavid van Moolenbroek 		return;
2099*83ee113eSDavid van Moolenbroek 	}
2100*83ee113eSDavid van Moolenbroek 
2101*83ee113eSDavid van Moolenbroek 	/* If we had a problem with our key or zone try again */
2102*83ee113eSDavid van Moolenbroek 	if ((eresult == DNS_R_NOTAUTH) ||
2103*83ee113eSDavid van Moolenbroek 	    (eresult == DNS_R_NOTZONE)) {
2104*83ee113eSDavid van Moolenbroek 		int i;
2105*83ee113eSDavid van Moolenbroek 		/* Our zone information was questionable,
2106*83ee113eSDavid van Moolenbroek 		 * repudiate it and try again */
2107*83ee113eSDavid van Moolenbroek 		log_error("DDNS: bad zone information, repudiating zone %s",
2108*83ee113eSDavid van Moolenbroek 			  ddns_cb->zone_name);
2109*83ee113eSDavid van Moolenbroek 		repudiate_zone(&ddns_cb->zone);
2110*83ee113eSDavid van Moolenbroek 		ddns_cb->zone_name[0]    = 0;
2111*83ee113eSDavid van Moolenbroek 		ISC_LIST_INIT(ddns_cb->zone_server_list);
2112*83ee113eSDavid van Moolenbroek 		for (i = 0; i < DHCP_MAXNS; i++) {
2113*83ee113eSDavid van Moolenbroek 			ISC_LINK_INIT(&ddns_cb->zone_addrs[i], link);
2114*83ee113eSDavid van Moolenbroek 		}
2115*83ee113eSDavid van Moolenbroek 
2116*83ee113eSDavid van Moolenbroek 		if ((ddns_cb->state == DDNS_STATE_ADD_PTR) ||
2117*83ee113eSDavid van Moolenbroek 		    (ddns_cb->state == DDNS_STATE_REM_PTR)) {
2118*83ee113eSDavid van Moolenbroek 			result = ddns_modify_ptr(ddns_cb, MDL);
2119*83ee113eSDavid van Moolenbroek 		} else {
2120*83ee113eSDavid van Moolenbroek 			result = ddns_modify_fwd(ddns_cb, MDL);
2121*83ee113eSDavid van Moolenbroek 		}
2122*83ee113eSDavid van Moolenbroek 
2123*83ee113eSDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
2124*83ee113eSDavid van Moolenbroek 			/* if we couldn't redo the query log it and
2125*83ee113eSDavid van Moolenbroek 			 * let the next function clean it up */
2126*83ee113eSDavid van Moolenbroek 			log_info("DDNS: Failed to retry after zone failure");
2127*83ee113eSDavid van Moolenbroek 			ddns_cb->cur_func(ddns_cb, result);
2128*83ee113eSDavid van Moolenbroek 		}
2129*83ee113eSDavid van Moolenbroek 		return;
2130*83ee113eSDavid van Moolenbroek 	} else {
2131*83ee113eSDavid van Moolenbroek 		/* pass it along to be processed */
2132*83ee113eSDavid van Moolenbroek 		ddns_cb->cur_func(ddns_cb, eresult);
2133*83ee113eSDavid van Moolenbroek 	}
2134*83ee113eSDavid van Moolenbroek 
2135*83ee113eSDavid van Moolenbroek 	return;
2136*83ee113eSDavid van Moolenbroek }
2137*83ee113eSDavid van Moolenbroek 
2138*83ee113eSDavid van Moolenbroek /*
2139*83ee113eSDavid van Moolenbroek  * This routine does the generic work for sending a ddns message to
2140*83ee113eSDavid van Moolenbroek  * modify the forward record (A or AAAA) and calls one of a set of
2141*83ee113eSDavid van Moolenbroek  * routines to build the specific message.
2142*83ee113eSDavid van Moolenbroek  */
2143*83ee113eSDavid van Moolenbroek 
2144*83ee113eSDavid van Moolenbroek isc_result_t
ddns_modify_fwd(dhcp_ddns_cb_t * ddns_cb,const char * file,int line)2145*83ee113eSDavid van Moolenbroek ddns_modify_fwd(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
2146*83ee113eSDavid van Moolenbroek {
2147*83ee113eSDavid van Moolenbroek 	isc_result_t result;
2148*83ee113eSDavid van Moolenbroek 	dns_tsec_t *tsec_key = NULL;
2149*83ee113eSDavid van Moolenbroek 
2150*83ee113eSDavid van Moolenbroek 	unsigned char *clientname;
2151*83ee113eSDavid van Moolenbroek 	dhcp_ddns_data_t *dataspace = NULL;
2152*83ee113eSDavid van Moolenbroek 	dns_namelist_t prereqlist, updatelist;
2153*83ee113eSDavid van Moolenbroek 	dns_fixedname_t zname0, pname0, uname0;
2154*83ee113eSDavid van Moolenbroek 	dns_name_t *zname = NULL, *pname, *uname;
2155*83ee113eSDavid van Moolenbroek 
2156*83ee113eSDavid van Moolenbroek 	isc_sockaddrlist_t *zlist = NULL;
2157*83ee113eSDavid van Moolenbroek 
2158*83ee113eSDavid van Moolenbroek 	/* Get a pointer to the clientname to make things easier. */
2159*83ee113eSDavid van Moolenbroek 	clientname = (unsigned char *)ddns_cb->fwd_name.data;
2160*83ee113eSDavid van Moolenbroek 
2161*83ee113eSDavid van Moolenbroek 	/* Extract and validate the type of the address. */
2162*83ee113eSDavid van Moolenbroek 	if (ddns_cb->address.len == 4) {
2163*83ee113eSDavid van Moolenbroek 		ddns_cb->address_type = dns_rdatatype_a;
2164*83ee113eSDavid van Moolenbroek 	} else if (ddns_cb->address.len == 16) {
2165*83ee113eSDavid van Moolenbroek 		ddns_cb->address_type = dns_rdatatype_aaaa;
2166*83ee113eSDavid van Moolenbroek 	} else {
2167*83ee113eSDavid van Moolenbroek 		return DHCP_R_INVALIDARG;
2168*83ee113eSDavid van Moolenbroek 	}
2169*83ee113eSDavid van Moolenbroek 
2170*83ee113eSDavid van Moolenbroek 	/*
2171*83ee113eSDavid van Moolenbroek 	 * If we already have a zone use it, otherwise try to lookup the
2172*83ee113eSDavid van Moolenbroek 	 * zone in our cache.  If we find one we will have a pointer to
2173*83ee113eSDavid van Moolenbroek 	 * the zone that needs to be dereferenced when we are done with it.
2174*83ee113eSDavid van Moolenbroek 	 * If we don't find one that is okay we'll let the DNS code try and
2175*83ee113eSDavid van Moolenbroek 	 * find the information for us.
2176*83ee113eSDavid van Moolenbroek 	 */
2177*83ee113eSDavid van Moolenbroek 
2178*83ee113eSDavid van Moolenbroek 	if (ddns_cb->zone == NULL) {
2179*83ee113eSDavid van Moolenbroek 		result = find_cached_zone(ddns_cb, FIND_FORWARD);
2180*83ee113eSDavid van Moolenbroek #if defined (DNS_ZONE_LOOKUP)
2181*83ee113eSDavid van Moolenbroek 		if (result == ISC_R_NOTFOUND) {
2182*83ee113eSDavid van Moolenbroek 			/*
2183*83ee113eSDavid van Moolenbroek 			 * We didn't find a cached zone, see if we can
2184*83ee113eSDavid van Moolenbroek 			 * can find a nameserver and create a zone.
2185*83ee113eSDavid van Moolenbroek 			 */
2186*83ee113eSDavid van Moolenbroek 			if (find_zone_start(ddns_cb, FIND_FORWARD)
2187*83ee113eSDavid van Moolenbroek 			    == ISC_R_SUCCESS) {
2188*83ee113eSDavid van Moolenbroek 				/*
2189*83ee113eSDavid van Moolenbroek 				 * We have started the process to find a zone
2190*83ee113eSDavid van Moolenbroek 				 * queue the ddns_cb for processing after we
2191*83ee113eSDavid van Moolenbroek 				 * create the zone
2192*83ee113eSDavid van Moolenbroek 				 */
2193*83ee113eSDavid van Moolenbroek 				/* sar - not yet implemented, currently we just
2194*83ee113eSDavid van Moolenbroek 				 * arrange for things to get cleaned up
2195*83ee113eSDavid van Moolenbroek 				 */
2196*83ee113eSDavid van Moolenbroek 				goto cleanup;
2197*83ee113eSDavid van Moolenbroek 			}
2198*83ee113eSDavid van Moolenbroek 		}
2199*83ee113eSDavid van Moolenbroek #endif
2200*83ee113eSDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
2201*83ee113eSDavid van Moolenbroek 			goto cleanup;
2202*83ee113eSDavid van Moolenbroek 	}
2203*83ee113eSDavid van Moolenbroek 
2204*83ee113eSDavid van Moolenbroek 	/*
2205*83ee113eSDavid van Moolenbroek 	 * If we have a zone try to get any information we need
2206*83ee113eSDavid van Moolenbroek 	 * from it - name, addresses and the key.  The address
2207*83ee113eSDavid van Moolenbroek 	 * and key may be empty the name can't be.
2208*83ee113eSDavid van Moolenbroek 	 */
2209*83ee113eSDavid van Moolenbroek 	if (ddns_cb->zone) {
2210*83ee113eSDavid van Moolenbroek 		/* Set up the zone name for use by DNS */
2211*83ee113eSDavid van Moolenbroek 		result = dhcp_isc_name(ddns_cb->zone_name, &zname0, &zname);
2212*83ee113eSDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
2213*83ee113eSDavid van Moolenbroek 			log_error("Unable to build name for zone for "
2214*83ee113eSDavid van Moolenbroek 				  "fwd update: %s %s",
2215*83ee113eSDavid van Moolenbroek 				  ddns_cb->zone_name,
2216*83ee113eSDavid van Moolenbroek 				  isc_result_totext(result));
2217*83ee113eSDavid van Moolenbroek 			goto cleanup;
2218*83ee113eSDavid van Moolenbroek 		}
2219*83ee113eSDavid van Moolenbroek 
2220*83ee113eSDavid van Moolenbroek 		if (!(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) {
2221*83ee113eSDavid van Moolenbroek 			/* If we have any addresses get them */
2222*83ee113eSDavid van Moolenbroek 			zlist = &ddns_cb->zone_server_list;
2223*83ee113eSDavid van Moolenbroek 		}
2224*83ee113eSDavid van Moolenbroek 
2225*83ee113eSDavid van Moolenbroek 
2226*83ee113eSDavid van Moolenbroek 		if (ddns_cb->zone->key != NULL) {
2227*83ee113eSDavid van Moolenbroek 			/*
2228*83ee113eSDavid van Moolenbroek 			 * Not having a key is fine, having a key
2229*83ee113eSDavid van Moolenbroek 			 * but not a tsec is odd so we warn the user.
2230*83ee113eSDavid van Moolenbroek 			 */
2231*83ee113eSDavid van Moolenbroek 			/*sar*/
2232*83ee113eSDavid van Moolenbroek 			/* should we do the warning? */
2233*83ee113eSDavid van Moolenbroek 			tsec_key = ddns_cb->zone->key->tsec_key;
2234*83ee113eSDavid van Moolenbroek 			if (tsec_key == NULL) {
2235*83ee113eSDavid van Moolenbroek 				log_error("No tsec for use with key %s",
2236*83ee113eSDavid van Moolenbroek 					  ddns_cb->zone->key->name);
2237*83ee113eSDavid van Moolenbroek 			}
2238*83ee113eSDavid van Moolenbroek 		}
2239*83ee113eSDavid van Moolenbroek 	}
2240*83ee113eSDavid van Moolenbroek 
2241*83ee113eSDavid van Moolenbroek 	/* Set up the DNS names for the prereq and update lists */
2242*83ee113eSDavid van Moolenbroek 	if (((result = dhcp_isc_name(clientname, &pname0, &pname))
2243*83ee113eSDavid van Moolenbroek 	     != ISC_R_SUCCESS) ||
2244*83ee113eSDavid van Moolenbroek 	    ((result = dhcp_isc_name(clientname, &uname0, &uname))
2245*83ee113eSDavid van Moolenbroek 	     != ISC_R_SUCCESS)) {
2246*83ee113eSDavid van Moolenbroek 		log_error("Unable to build name for fwd update: %s %s",
2247*83ee113eSDavid van Moolenbroek 			  clientname, isc_result_totext(result));
2248*83ee113eSDavid van Moolenbroek 		goto cleanup;
2249*83ee113eSDavid van Moolenbroek 	}
2250*83ee113eSDavid van Moolenbroek 
2251*83ee113eSDavid van Moolenbroek 	/* Allocate the various isc dns library structures we may require. */
2252*83ee113eSDavid van Moolenbroek 	dataspace = isc_mem_get(dhcp_gbl_ctx.mctx, sizeof(*dataspace) * 4);
2253*83ee113eSDavid van Moolenbroek 	if (dataspace == NULL) {
2254*83ee113eSDavid van Moolenbroek 		log_error("Unable to allocate memory for fwd update");
2255*83ee113eSDavid van Moolenbroek 		result = ISC_R_NOMEMORY;
2256*83ee113eSDavid van Moolenbroek 		goto cleanup;
2257*83ee113eSDavid van Moolenbroek 	}
2258*83ee113eSDavid van Moolenbroek 
2259*83ee113eSDavid van Moolenbroek 	ISC_LIST_INIT(prereqlist);
2260*83ee113eSDavid van Moolenbroek 	ISC_LIST_INIT(updatelist);
2261*83ee113eSDavid van Moolenbroek 
2262*83ee113eSDavid van Moolenbroek 	switch(ddns_cb->state) {
2263*83ee113eSDavid van Moolenbroek 	case DDNS_STATE_ADD_FW_NXDOMAIN:
2264*83ee113eSDavid van Moolenbroek 		result = ddns_modify_fwd_add1(ddns_cb, dataspace,
2265*83ee113eSDavid van Moolenbroek 					      pname, uname);
2266*83ee113eSDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
2267*83ee113eSDavid van Moolenbroek 			goto cleanup;
2268*83ee113eSDavid van Moolenbroek 		}
2269*83ee113eSDavid van Moolenbroek 		ISC_LIST_APPEND(prereqlist, pname, link);
2270*83ee113eSDavid van Moolenbroek 		break;
2271*83ee113eSDavid van Moolenbroek 	case DDNS_STATE_ADD_FW_YXDHCID:
2272*83ee113eSDavid van Moolenbroek 		result = ddns_modify_fwd_add2(ddns_cb, dataspace,
2273*83ee113eSDavid van Moolenbroek 					       pname, uname);
2274*83ee113eSDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
2275*83ee113eSDavid van Moolenbroek 			goto cleanup;
2276*83ee113eSDavid van Moolenbroek 		}
2277*83ee113eSDavid van Moolenbroek 
2278*83ee113eSDavid van Moolenbroek 		/* If we aren't doing conflict override we have entries
2279*83ee113eSDavid van Moolenbroek 		 * in the pname list and we need to attach it to the
2280*83ee113eSDavid van Moolenbroek 		 * prereqlist */
2281*83ee113eSDavid van Moolenbroek 
2282*83ee113eSDavid van Moolenbroek 		if ((ddns_cb->flags & DDNS_CONFLICT_OVERRIDE) == 0) {
2283*83ee113eSDavid van Moolenbroek 			ISC_LIST_APPEND(prereqlist, pname, link);
2284*83ee113eSDavid van Moolenbroek 		}
2285*83ee113eSDavid van Moolenbroek 
2286*83ee113eSDavid van Moolenbroek 		break;
2287*83ee113eSDavid van Moolenbroek 	case DDNS_STATE_REM_FW_YXDHCID:
2288*83ee113eSDavid van Moolenbroek 		result = ddns_modify_fwd_rem1(ddns_cb, dataspace,
2289*83ee113eSDavid van Moolenbroek 					      pname, uname);
2290*83ee113eSDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
2291*83ee113eSDavid van Moolenbroek 			goto cleanup;
2292*83ee113eSDavid van Moolenbroek 		}
2293*83ee113eSDavid van Moolenbroek 		ISC_LIST_APPEND(prereqlist, pname, link);
2294*83ee113eSDavid van Moolenbroek 		break;
2295*83ee113eSDavid van Moolenbroek 	case DDNS_STATE_REM_FW_NXRR:
2296*83ee113eSDavid van Moolenbroek 		result = ddns_modify_fwd_rem2(ddns_cb, dataspace,
2297*83ee113eSDavid van Moolenbroek 					      pname, uname);
2298*83ee113eSDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
2299*83ee113eSDavid van Moolenbroek 			goto cleanup;
2300*83ee113eSDavid van Moolenbroek 		}
2301*83ee113eSDavid van Moolenbroek 		ISC_LIST_APPEND(prereqlist, pname, link);
2302*83ee113eSDavid van Moolenbroek 		break;
2303*83ee113eSDavid van Moolenbroek 
2304*83ee113eSDavid van Moolenbroek 	default:
2305*83ee113eSDavid van Moolenbroek 		log_error("Invalid operation in ddns code.");
2306*83ee113eSDavid van Moolenbroek 		result = DHCP_R_INVALIDARG;
2307*83ee113eSDavid van Moolenbroek 		goto cleanup;
2308*83ee113eSDavid van Moolenbroek 		break;
2309*83ee113eSDavid van Moolenbroek 	}
2310*83ee113eSDavid van Moolenbroek 
2311*83ee113eSDavid van Moolenbroek 	/*
2312*83ee113eSDavid van Moolenbroek 	 * We always have an update list but may not have a prereqlist
2313*83ee113eSDavid van Moolenbroek 	 * if we are doing conflict override.
2314*83ee113eSDavid van Moolenbroek 	 */
2315*83ee113eSDavid van Moolenbroek 	ISC_LIST_APPEND(updatelist, uname, link);
2316*83ee113eSDavid van Moolenbroek 
2317*83ee113eSDavid van Moolenbroek 	/* send the message, cleanup and return the result */
2318*83ee113eSDavid van Moolenbroek 	result = ddns_update(dhcp_gbl_ctx.dnsclient,
2319*83ee113eSDavid van Moolenbroek 			     dns_rdataclass_in, zname,
2320*83ee113eSDavid van Moolenbroek 			     &prereqlist, &updatelist,
2321*83ee113eSDavid van Moolenbroek 			     zlist, tsec_key,
2322*83ee113eSDavid van Moolenbroek 			     DNS_CLIENTRESOPT_ALLOWRUN,
2323*83ee113eSDavid van Moolenbroek 			     dhcp_gbl_ctx.task,
2324*83ee113eSDavid van Moolenbroek 			     ddns_interlude,
2325*83ee113eSDavid van Moolenbroek 			     (void *)ddns_cb,
2326*83ee113eSDavid van Moolenbroek 			     &ddns_cb->transaction);
2327*83ee113eSDavid van Moolenbroek 	if (result == ISC_R_FAMILYNOSUPPORT) {
2328*83ee113eSDavid van Moolenbroek 		log_info("Unable to perform DDNS update, "
2329*83ee113eSDavid van Moolenbroek 			 "address family not supported");
2330*83ee113eSDavid van Moolenbroek 	}
2331*83ee113eSDavid van Moolenbroek 
2332*83ee113eSDavid van Moolenbroek #if defined (DEBUG_DNS_UPDATES)
2333*83ee113eSDavid van Moolenbroek 	print_dns_status(DDNS_PRINT_OUTBOUND, ddns_cb, result);
2334*83ee113eSDavid van Moolenbroek #endif
2335*83ee113eSDavid van Moolenbroek 
2336*83ee113eSDavid van Moolenbroek  cleanup:
2337*83ee113eSDavid van Moolenbroek #if defined (DEBUG_DNS_UPDATES)
2338*83ee113eSDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
2339*83ee113eSDavid van Moolenbroek 		log_info("DDNS: %s(%d): error in ddns_modify_fwd %s for %p",
2340*83ee113eSDavid van Moolenbroek 			 file, line, isc_result_totext(result), ddns_cb);
2341*83ee113eSDavid van Moolenbroek 	}
2342*83ee113eSDavid van Moolenbroek #endif
2343*83ee113eSDavid van Moolenbroek 
2344*83ee113eSDavid van Moolenbroek 	if (dataspace != NULL) {
2345*83ee113eSDavid van Moolenbroek 		isc_mem_put(dhcp_gbl_ctx.mctx, dataspace,
2346*83ee113eSDavid van Moolenbroek 			    sizeof(*dataspace) * 4);
2347*83ee113eSDavid van Moolenbroek 	}
2348*83ee113eSDavid van Moolenbroek 	return(result);
2349*83ee113eSDavid van Moolenbroek }
2350*83ee113eSDavid van Moolenbroek 
2351*83ee113eSDavid van Moolenbroek 
2352*83ee113eSDavid van Moolenbroek isc_result_t
ddns_modify_ptr(dhcp_ddns_cb_t * ddns_cb,const char * file,int line)2353*83ee113eSDavid van Moolenbroek ddns_modify_ptr(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
2354*83ee113eSDavid van Moolenbroek {
2355*83ee113eSDavid van Moolenbroek 	isc_result_t result;
2356*83ee113eSDavid van Moolenbroek 	dns_tsec_t *tsec_key  = NULL;
2357*83ee113eSDavid van Moolenbroek 	unsigned char *ptrname;
2358*83ee113eSDavid van Moolenbroek 	dhcp_ddns_data_t *dataspace = NULL;
2359*83ee113eSDavid van Moolenbroek 	dns_namelist_t updatelist;
2360*83ee113eSDavid van Moolenbroek 	dns_fixedname_t zname0, uname0;
2361*83ee113eSDavid van Moolenbroek 	dns_name_t *zname = NULL, *uname;
2362*83ee113eSDavid van Moolenbroek 	isc_sockaddrlist_t *zlist = NULL;
2363*83ee113eSDavid van Moolenbroek 	unsigned char buf[256];
2364*83ee113eSDavid van Moolenbroek 	int buflen;
2365*83ee113eSDavid van Moolenbroek 
2366*83ee113eSDavid van Moolenbroek 	/*
2367*83ee113eSDavid van Moolenbroek 	 * Try to lookup the zone in the zone cache.  As with the forward
2368*83ee113eSDavid van Moolenbroek 	 * case it's okay if we don't have one, the DNS code will try to
2369*83ee113eSDavid van Moolenbroek 	 * find something also if we succeed we will need to dereference
2370*83ee113eSDavid van Moolenbroek 	 * the zone later.  Unlike with the forward case we assume we won't
2371*83ee113eSDavid van Moolenbroek 	 * have a pre-existing zone.
2372*83ee113eSDavid van Moolenbroek 	 */
2373*83ee113eSDavid van Moolenbroek 	result = find_cached_zone(ddns_cb, FIND_REVERSE);
2374*83ee113eSDavid van Moolenbroek 
2375*83ee113eSDavid van Moolenbroek #if defined (DNS_ZONE_LOOKUP)
2376*83ee113eSDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND) {
2377*83ee113eSDavid van Moolenbroek 		/*
2378*83ee113eSDavid van Moolenbroek 		 * We didn't find a cached zone, see if we can
2379*83ee113eSDavid van Moolenbroek 		 * can find a nameserver and create a zone.
2380*83ee113eSDavid van Moolenbroek 		 */
2381*83ee113eSDavid van Moolenbroek 		if (find_zone_start(ddns_cb, FIND_REVERSE) == ISC_R_SUCCESS) {
2382*83ee113eSDavid van Moolenbroek 			/*
2383*83ee113eSDavid van Moolenbroek 			 * We have started the process to find a zone
2384*83ee113eSDavid van Moolenbroek 			 * queue the ddns_cb for processing after we
2385*83ee113eSDavid van Moolenbroek 			 * create the zone
2386*83ee113eSDavid van Moolenbroek 			 */
2387*83ee113eSDavid van Moolenbroek 			/* sar - not yet implemented, currently we just
2388*83ee113eSDavid van Moolenbroek 			 * arrange for things to get cleaned up
2389*83ee113eSDavid van Moolenbroek 			 */
2390*83ee113eSDavid van Moolenbroek 			goto cleanup;
2391*83ee113eSDavid van Moolenbroek 		}
2392*83ee113eSDavid van Moolenbroek 	}
2393*83ee113eSDavid van Moolenbroek #endif
2394*83ee113eSDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
2395*83ee113eSDavid van Moolenbroek 		goto cleanup;
2396*83ee113eSDavid van Moolenbroek 
2397*83ee113eSDavid van Moolenbroek 
2398*83ee113eSDavid van Moolenbroek 	if ((result == ISC_R_SUCCESS) &&
2399*83ee113eSDavid van Moolenbroek 	    !(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) {
2400*83ee113eSDavid van Moolenbroek 		/* Set up the zone name for use by DNS */
2401*83ee113eSDavid van Moolenbroek 		result = dhcp_isc_name(ddns_cb->zone_name, &zname0, &zname);
2402*83ee113eSDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
2403*83ee113eSDavid van Moolenbroek 			log_error("Unable to build name for zone for "
2404*83ee113eSDavid van Moolenbroek 				  "fwd update: %s %s",
2405*83ee113eSDavid van Moolenbroek 				  ddns_cb->zone_name,
2406*83ee113eSDavid van Moolenbroek 				  isc_result_totext(result));
2407*83ee113eSDavid van Moolenbroek 			goto cleanup;
2408*83ee113eSDavid van Moolenbroek 		}
2409*83ee113eSDavid van Moolenbroek 		/* If we have any addresses get them */
2410*83ee113eSDavid van Moolenbroek 		if (!(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) {
2411*83ee113eSDavid van Moolenbroek 			zlist = &ddns_cb->zone_server_list;
2412*83ee113eSDavid van Moolenbroek 		}
2413*83ee113eSDavid van Moolenbroek 
2414*83ee113eSDavid van Moolenbroek 		/*
2415*83ee113eSDavid van Moolenbroek 		 * If we now have a zone try to get the key, NULL is okay,
2416*83ee113eSDavid van Moolenbroek 		 * having a key but not a tsec is odd so we warn.
2417*83ee113eSDavid van Moolenbroek 		 */
2418*83ee113eSDavid van Moolenbroek 		/*sar*/
2419*83ee113eSDavid van Moolenbroek 		/* should we do the warning if we have a key but no tsec? */
2420*83ee113eSDavid van Moolenbroek 		if ((ddns_cb->zone != NULL) && (ddns_cb->zone->key != NULL)) {
2421*83ee113eSDavid van Moolenbroek 			tsec_key = ddns_cb->zone->key->tsec_key;
2422*83ee113eSDavid van Moolenbroek 			if (tsec_key == NULL) {
2423*83ee113eSDavid van Moolenbroek 				log_error("No tsec for use with key %s",
2424*83ee113eSDavid van Moolenbroek 					  ddns_cb->zone->key->name);
2425*83ee113eSDavid van Moolenbroek 			}
2426*83ee113eSDavid van Moolenbroek 		}
2427*83ee113eSDavid van Moolenbroek 	}
2428*83ee113eSDavid van Moolenbroek 
2429*83ee113eSDavid van Moolenbroek 	/* We must have a name for the update list */
2430*83ee113eSDavid van Moolenbroek 	/* Get a pointer to the ptrname to make things easier. */
2431*83ee113eSDavid van Moolenbroek 	ptrname = (unsigned char *)ddns_cb->rev_name.data;
2432*83ee113eSDavid van Moolenbroek 
2433*83ee113eSDavid van Moolenbroek 	if ((result = dhcp_isc_name(ptrname, &uname0, &uname))
2434*83ee113eSDavid van Moolenbroek 	     != ISC_R_SUCCESS) {
2435*83ee113eSDavid van Moolenbroek 		log_error("Unable to build name for fwd update: %s %s",
2436*83ee113eSDavid van Moolenbroek 			  ptrname, isc_result_totext(result));
2437*83ee113eSDavid van Moolenbroek 		goto cleanup;
2438*83ee113eSDavid van Moolenbroek 	}
2439*83ee113eSDavid van Moolenbroek 
2440*83ee113eSDavid van Moolenbroek 	/*
2441*83ee113eSDavid van Moolenbroek 	 * Allocate the various isc dns library structures we may require.
2442*83ee113eSDavid van Moolenbroek 	 * Allocating one blob avoids being halfway through the process
2443*83ee113eSDavid van Moolenbroek 	 * and being unable to allocate as well as making the free easy.
2444*83ee113eSDavid van Moolenbroek 	 */
2445*83ee113eSDavid van Moolenbroek 	dataspace = isc_mem_get(dhcp_gbl_ctx.mctx, sizeof(*dataspace) * 2);
2446*83ee113eSDavid van Moolenbroek 	if (dataspace == NULL) {
2447*83ee113eSDavid van Moolenbroek 		log_error("Unable to allocate memory for fwd update");
2448*83ee113eSDavid van Moolenbroek 		result = ISC_R_NOMEMORY;
2449*83ee113eSDavid van Moolenbroek 		goto cleanup;
2450*83ee113eSDavid van Moolenbroek 	}
2451*83ee113eSDavid van Moolenbroek 
2452*83ee113eSDavid van Moolenbroek 	ISC_LIST_INIT(updatelist);
2453*83ee113eSDavid van Moolenbroek 
2454*83ee113eSDavid van Moolenbroek 	/*
2455*83ee113eSDavid van Moolenbroek 	 * Construct the update list
2456*83ee113eSDavid van Moolenbroek 	 * We always delete what's currently there
2457*83ee113eSDavid van Moolenbroek 	 * Delete PTR RR.
2458*83ee113eSDavid van Moolenbroek 	 */
2459*83ee113eSDavid van Moolenbroek 	result = make_dns_dataset(dns_rdataclass_any, dns_rdatatype_ptr,
2460*83ee113eSDavid van Moolenbroek 				  &dataspace[0], NULL, 0, 0);
2461*83ee113eSDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
2462*83ee113eSDavid van Moolenbroek 		goto cleanup;
2463*83ee113eSDavid van Moolenbroek 	}
2464*83ee113eSDavid van Moolenbroek 	ISC_LIST_APPEND(uname->list, &dataspace[0].rdataset, link);
2465*83ee113eSDavid van Moolenbroek 
2466*83ee113eSDavid van Moolenbroek 	/*
2467*83ee113eSDavid van Moolenbroek 	 * If we are updating the pointer we then add the new one
2468*83ee113eSDavid van Moolenbroek 	 * Add PTR RR.
2469*83ee113eSDavid van Moolenbroek 	 */
2470*83ee113eSDavid van Moolenbroek 	if (ddns_cb->state == DDNS_STATE_ADD_PTR) {
2471*83ee113eSDavid van Moolenbroek #if 0
2472*83ee113eSDavid van Moolenbroek 		/*
2473*83ee113eSDavid van Moolenbroek 		 * I've left this dead code in the file  for now in case
2474*83ee113eSDavid van Moolenbroek 		 * we decide to try and get rid of the ns_name functions.
2475*83ee113eSDavid van Moolenbroek 		 * sar
2476*83ee113eSDavid van Moolenbroek 		 */
2477*83ee113eSDavid van Moolenbroek 
2478*83ee113eSDavid van Moolenbroek 		/*
2479*83ee113eSDavid van Moolenbroek 		 * Need to convert pointer into on the wire representation
2480*83ee113eSDavid van Moolenbroek 		 * We replace the '.' characters with the lengths of the
2481*83ee113eSDavid van Moolenbroek 		 * next name and add a length to the beginning for the first
2482*83ee113eSDavid van Moolenbroek 		 * name.
2483*83ee113eSDavid van Moolenbroek 		 */
2484*83ee113eSDavid van Moolenbroek 		if (ddns_cb->fwd_name.len == 1) {
2485*83ee113eSDavid van Moolenbroek 			/* the root */
2486*83ee113eSDavid van Moolenbroek 			buf[0] = 0;
2487*83ee113eSDavid van Moolenbroek 			buflen = 1;
2488*83ee113eSDavid van Moolenbroek 		} else {
2489*83ee113eSDavid van Moolenbroek 			unsigned char *cp;
2490*83ee113eSDavid van Moolenbroek 			buf[0] = '.';
2491*83ee113eSDavid van Moolenbroek 			memcpy(&buf[1], ddns_cb->fwd_name.data,
2492*83ee113eSDavid van Moolenbroek 			       ddns_cb->fwd_name.len);
2493*83ee113eSDavid van Moolenbroek 			for(cp = buf + ddns_cb->fwd_name.len, buflen = 0;
2494*83ee113eSDavid van Moolenbroek 			    cp != buf;
2495*83ee113eSDavid van Moolenbroek 			    cp--) {
2496*83ee113eSDavid van Moolenbroek 				if (*cp == '.') {
2497*83ee113eSDavid van Moolenbroek 					*cp = buflen;
2498*83ee113eSDavid van Moolenbroek 					buflen = 0;
2499*83ee113eSDavid van Moolenbroek 				} else {
2500*83ee113eSDavid van Moolenbroek 					buflen++;
2501*83ee113eSDavid van Moolenbroek 				}
2502*83ee113eSDavid van Moolenbroek 			}
2503*83ee113eSDavid van Moolenbroek 			*cp = buflen;
2504*83ee113eSDavid van Moolenbroek 			buflen = ddns_cb->fwd_name.len + 1;
2505*83ee113eSDavid van Moolenbroek 		}
2506*83ee113eSDavid van Moolenbroek #endif
2507*83ee113eSDavid van Moolenbroek 		/*
2508*83ee113eSDavid van Moolenbroek 		 * Need to convert pointer into on the wire representation
2509*83ee113eSDavid van Moolenbroek 		 */
2510*83ee113eSDavid van Moolenbroek 		if (MRns_name_pton((char *)ddns_cb->fwd_name.data,
2511*83ee113eSDavid van Moolenbroek 				   buf, 256) == -1) {
2512*83ee113eSDavid van Moolenbroek 			goto cleanup;
2513*83ee113eSDavid van Moolenbroek 		}
2514*83ee113eSDavid van Moolenbroek 		buflen = 0;
2515*83ee113eSDavid van Moolenbroek 		while (buf[buflen] != 0) {
2516*83ee113eSDavid van Moolenbroek 			buflen += buf[buflen] + 1;
2517*83ee113eSDavid van Moolenbroek 		}
2518*83ee113eSDavid van Moolenbroek 		buflen++;
2519*83ee113eSDavid van Moolenbroek 
2520*83ee113eSDavid van Moolenbroek 		result = make_dns_dataset(dns_rdataclass_in,
2521*83ee113eSDavid van Moolenbroek 					  dns_rdatatype_ptr,
2522*83ee113eSDavid van Moolenbroek 					  &dataspace[1],
2523*83ee113eSDavid van Moolenbroek 					  buf, buflen, ddns_cb->ttl);
2524*83ee113eSDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
2525*83ee113eSDavid van Moolenbroek 			goto cleanup;
2526*83ee113eSDavid van Moolenbroek 		}
2527*83ee113eSDavid van Moolenbroek 		ISC_LIST_APPEND(uname->list, &dataspace[1].rdataset, link);
2528*83ee113eSDavid van Moolenbroek 	}
2529*83ee113eSDavid van Moolenbroek 
2530*83ee113eSDavid van Moolenbroek 	ISC_LIST_APPEND(updatelist, uname, link);
2531*83ee113eSDavid van Moolenbroek 
2532*83ee113eSDavid van Moolenbroek 	/*sar*/
2533*83ee113eSDavid van Moolenbroek 	/*
2534*83ee113eSDavid van Moolenbroek 	 * for now I'll cleanup the dataset immediately, it would be
2535*83ee113eSDavid van Moolenbroek 	 * more efficient to keep it around in case the signaturure failed
2536*83ee113eSDavid van Moolenbroek 	 * and we wanted to retry it.
2537*83ee113eSDavid van Moolenbroek 	 */
2538*83ee113eSDavid van Moolenbroek 	/* send the message, cleanup and return the result */
2539*83ee113eSDavid van Moolenbroek 	result = ddns_update((dns_client_t *)dhcp_gbl_ctx.dnsclient,
2540*83ee113eSDavid van Moolenbroek 			     dns_rdataclass_in, zname,
2541*83ee113eSDavid van Moolenbroek 			     NULL, &updatelist,
2542*83ee113eSDavid van Moolenbroek 			     zlist, tsec_key,
2543*83ee113eSDavid van Moolenbroek 			     DNS_CLIENTRESOPT_ALLOWRUN,
2544*83ee113eSDavid van Moolenbroek 			     dhcp_gbl_ctx.task,
2545*83ee113eSDavid van Moolenbroek 			     ddns_interlude, (void *)ddns_cb,
2546*83ee113eSDavid van Moolenbroek 			     &ddns_cb->transaction);
2547*83ee113eSDavid van Moolenbroek 	if (result == ISC_R_FAMILYNOSUPPORT) {
2548*83ee113eSDavid van Moolenbroek 		log_info("Unable to perform DDNS update, "
2549*83ee113eSDavid van Moolenbroek 			 "address family not supported");
2550*83ee113eSDavid van Moolenbroek 	}
2551*83ee113eSDavid van Moolenbroek 
2552*83ee113eSDavid van Moolenbroek #if defined (DEBUG_DNS_UPDATES)
2553*83ee113eSDavid van Moolenbroek 	print_dns_status(DDNS_PRINT_OUTBOUND, ddns_cb, result);
2554*83ee113eSDavid van Moolenbroek #endif
2555*83ee113eSDavid van Moolenbroek 
2556*83ee113eSDavid van Moolenbroek  cleanup:
2557*83ee113eSDavid van Moolenbroek #if defined (DEBUG_DNS_UPDATES)
2558*83ee113eSDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
2559*83ee113eSDavid van Moolenbroek 		log_info("DDNS: %s(%d): error in ddns_modify_ptr %s for %p",
2560*83ee113eSDavid van Moolenbroek 			 file, line, isc_result_totext(result), ddns_cb);
2561*83ee113eSDavid van Moolenbroek 	}
2562*83ee113eSDavid van Moolenbroek #endif
2563*83ee113eSDavid van Moolenbroek 
2564*83ee113eSDavid van Moolenbroek 	if (dataspace != NULL) {
2565*83ee113eSDavid van Moolenbroek 		isc_mem_put(dhcp_gbl_ctx.mctx, dataspace,
2566*83ee113eSDavid van Moolenbroek 			    sizeof(*dataspace) * 2);
2567*83ee113eSDavid van Moolenbroek 	}
2568*83ee113eSDavid van Moolenbroek 	return(result);
2569*83ee113eSDavid van Moolenbroek }
2570*83ee113eSDavid van Moolenbroek 
2571*83ee113eSDavid van Moolenbroek void
ddns_cancel(dhcp_ddns_cb_t * ddns_cb,const char * file,int line)2572*83ee113eSDavid van Moolenbroek ddns_cancel(dhcp_ddns_cb_t *ddns_cb, const char *file, int line) {
2573*83ee113eSDavid van Moolenbroek 	ddns_cb->flags |= DDNS_ABORT;
2574*83ee113eSDavid van Moolenbroek 	if (ddns_cb->transaction != NULL) {
2575*83ee113eSDavid van Moolenbroek 		dns_client_cancelupdate((dns_clientupdatetrans_t *)
2576*83ee113eSDavid van Moolenbroek 					ddns_cb->transaction);
2577*83ee113eSDavid van Moolenbroek 	}
2578*83ee113eSDavid van Moolenbroek 	ddns_cb->lease = NULL;
2579*83ee113eSDavid van Moolenbroek 
2580*83ee113eSDavid van Moolenbroek #if defined (DEBUG_DNS_UPDATES)
2581*83ee113eSDavid van Moolenbroek 	log_info("DDNS: %s(%d): cancelling transaction for  %p",
2582*83ee113eSDavid van Moolenbroek 		 file, line,  ddns_cb);
2583*83ee113eSDavid van Moolenbroek #endif
2584*83ee113eSDavid van Moolenbroek }
2585*83ee113eSDavid van Moolenbroek 
2586*83ee113eSDavid van Moolenbroek #endif /* NSUPDATE */
2587*83ee113eSDavid van Moolenbroek 
2588*83ee113eSDavid van Moolenbroek HASH_FUNCTIONS (dns_zone, const char *, struct dns_zone, dns_zone_hash_t,
2589*83ee113eSDavid van Moolenbroek 		dns_zone_reference, dns_zone_dereference, do_case_hash)
2590