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