]> git.ipfire.org Git - thirdparty/dhcp.git/blob - common/dns.c
Go back to the BSD license.
[thirdparty/dhcp.git] / common / dns.c
1 /* dns.c
2
3 Domain Name Service subroutines. */
4
5 /*
6 * Copyright (c) 2000 Internet Software Consortium.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of The Internet Software Consortium nor the names
19 * of its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * This software has been written for the Internet Software Consortium
37 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
38 * To learn more about the Internet Software Consortium, see
39 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
40 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
41 * ``http://www.nominum.com''.
42 */
43
44 #ifndef lint
45 static char copyright[] =
46 "$Id: dns.c,v 1.18 2000/03/17 03:59:01 mellon Exp $ Copyright (c) 2000 The Internet Software Consortium. All rights reserved.\n";
47 #endif /* not lint */
48
49 #include "dhcpd.h"
50 #include "arpa/nameser.h"
51
52 /* This file is kind of a crutch for the BIND 8 nsupdate code, which has
53 * itself been cruelly hacked from its original state. What this code
54 * does is twofold: first, it maintains a database of zone cuts that can
55 * be used to figure out which server should be contacted to update any
56 * given domain name. Secondly, it maintains a set of named TSIG keys,
57 * and associates those keys with zones. When an update is requested for
58 * a particular zone, the key associated with that zone is used for the
59 * update.
60 *
61 * The way this works is that you define the domain name to which an
62 * SOA corresponds, and the addresses of some primaries for that domain name:
63 *
64 * zone FOO.COM {
65 * primary 10.0.17.1;
66 * secondary 10.0.22.1, 10.0.23.1;
67 * tsig-key "FOO.COM Key";
68 * }
69 *
70 * If an update is requested for GAZANGA.TOPANGA.FOO.COM, then the name
71 * server looks in its database for a zone record for "GAZANGA.TOPANGA.FOO.COM",
72 * doesn't find it, looks for one for "TOPANGA.FOO.COM", doesn't find *that*,
73 * looks for "FOO.COM", finds it. So it
74 * attempts the update to the primary for FOO.COM. If that times out, it
75 * tries the secondaries. You can list multiple primaries if you have some
76 * kind of magic name server that supports that. You shouldn't list
77 * secondaries that don't know how to forward updates (e.g., BIND 8 doesn't
78 * support update forwarding, AFAIK). If no TSIG key is listed, the update
79 * is attempted without TSIG.
80 *
81 * The DHCP server tries to find an existing zone for any given name by
82 * trying to look up a local zone structure for each domain containing
83 * that name, all the way up to '.'. If it finds one cached, it tries
84 * to use that one to do the update. That's why it tries to update
85 * "FOO.COM" above, even though theoretically it should try GAZANGA...
86 * and TOPANGA... first.
87 *
88 * If the update fails with a predefined or cached zone (we'll get to
89 * those in a second), then it tries to find a more specific zone. This
90 * is done by looking first for an SOA for GAZANGA.TOPANGA.FOO.COM. Then
91 * an SOA for TOPANGA.FOO.COM is sought. If during this search a predefined
92 * or cached zone is found, the update fails - there's something wrong
93 * somewhere.
94 *
95 * If a more specific zone _is_ found, that zone is cached for the length of
96 * its TTL in the same database as that described above. TSIG updates are
97 * never done for cached zones - if you want TSIG updates you _must_
98 * write a zone definition linking the key to the zone. In cases where you
99 * know for sure what the key is but do not want to hardcode the IP addresses
100 * of the primary or secondaries, a zone declaration can be made that doesn't
101 * include any primary or secondary declarations. When the DHCP server
102 * encounters this while hunting up a matching zone for a name, it looks up
103 * the SOA, fills in the IP addresses, and uses that record for the update.
104 * If the SOA lookup returns NXRRSET, a warning is printed and the zone is
105 * discarded, TSIG key and all. The search for the zone then continues as if
106 * the zone record hadn't been found. Zones without IP addresses don't
107 * match when initially hunting for a predefined or cached zone to update.
108 *
109 * When an update is attempted and no predefined or cached zone is found
110 * that matches any enclosing domain of the domain being updated, the DHCP
111 * server goes through the same process that is done when the update to a
112 * predefined or cached zone fails - starting with the most specific domain
113 * name (GAZANGA.TOPANGA.FOO.COM) and moving to the least specific (the root),
114 * it tries to look up an SOA record. When it finds one, it creates a cached
115 * zone and attempts an update, and gives up if the update fails.
116 *
117 * TSIG keys are defined like this:
118 *
119 * tsig-key "FOO.COM Key" HMAC-MD5.SIG-ALG.REG.INT <CSHL>;
120 *
121 * CSHL is a colon-seperated list of hexadecimal bytes that make up
122 * the key. It's also permissible to use a quoted string here - this will
123 * be translated as the ASCII bytes making up the string, and will not include
124 * any NUL termination. The key name can be any text string, and the
125 * key type must be one of the key types defined in the draft or by the IANA.
126 * Currently only the HMAC-MD5... key type is supported.
127 */
128
129 struct hash_table *tsig_key_hash;
130 struct hash_table *dns_zone_hash;
131
132 isc_result_t enter_dns_zone (struct dns_zone *zone)
133 {
134 struct dns_zone *tz;
135
136 if (dns_zone_hash) {
137 tz = hash_lookup (dns_zone_hash, zone -> name, 0);
138 if (tz == zone)
139 return ISC_R_SUCCESS;
140 if (tz)
141 delete_hash_entry (dns_zone_hash, zone -> name, 0);
142 } else {
143 dns_zone_hash =
144 new_hash ((hash_reference)dns_zone_reference,
145 (hash_dereference)dns_zone_dereference);
146 if (!dns_zone_hash)
147 return ISC_R_NOMEMORY;
148 }
149 add_hash (dns_zone_hash, zone -> name, 0, zone);
150 return ISC_R_SUCCESS;
151 }
152
153 isc_result_t dns_zone_lookup (struct dns_zone **zone, const char *name) {
154 struct dns_zone *tz;
155
156 if (!dns_zone_hash)
157 return ISC_R_NOTFOUND;
158 tz = hash_lookup (dns_zone_hash, name, 0);
159 if (!tz)
160 return ISC_R_NOTFOUND;
161 if (!dns_zone_reference (zone, tz, MDL))
162 return ISC_R_UNEXPECTED;
163 return ISC_R_SUCCESS;
164 }
165
166 isc_result_t enter_tsig_key (struct tsig_key *tkey)
167 {
168 struct tsig_key *tk;
169
170 if (tsig_key_hash) {
171 tk = hash_lookup (tsig_key_hash, tkey -> name, 0);
172 if (tk == tkey)
173 return ISC_R_SUCCESS;
174 if (tk)
175 delete_hash_entry (tsig_key_hash, tkey -> name, 0);
176 } else {
177 tsig_key_hash =
178 new_hash ((hash_reference)tsig_key_reference,
179 (hash_dereference)tsig_key_dereference);
180 if (!tsig_key_hash)
181 return ISC_R_NOMEMORY;
182 }
183 add_hash (tsig_key_hash, tkey -> name, 0, tkey);
184 return ISC_R_SUCCESS;
185
186 }
187
188 isc_result_t tsig_key_lookup (struct tsig_key **tkey, const char *name) {
189 struct tsig_key *tk;
190
191 if (!tsig_key_hash)
192 return ISC_R_NOTFOUND;
193 tk = hash_lookup (tsig_key_hash, name, 0);
194 if (!tk)
195 return ISC_R_NOTFOUND;
196 if (!tsig_key_reference (tkey, tk, MDL))
197 return ISC_R_UNEXPECTED;
198 return ISC_R_SUCCESS;
199 }
200
201 int dns_zone_dereference (ptr, file, line)
202 struct dns_zone **ptr;
203 const char *file;
204 int line;
205 {
206 int i;
207 struct dns_zone *dns_zone;
208
209 if (!ptr || !*ptr) {
210 log_error ("%s(%d): null pointer", file, line);
211 #if defined (POINTER_DEBUG)
212 abort ();
213 #else
214 return 0;
215 #endif
216 }
217
218 dns_zone = *ptr;
219 *ptr = (struct dns_zone *)0;
220 --dns_zone -> refcnt;
221 rc_register (file, line, ptr, dns_zone, dns_zone -> refcnt);
222 if (dns_zone -> refcnt > 0)
223 return 1;
224
225 if (dns_zone -> refcnt < 0) {
226 log_error ("%s(%d): negative refcnt!", file, line);
227 #if defined (DEBUG_RC_HISTORY)
228 dump_rc_history ();
229 #endif
230 #if defined (POINTER_DEBUG)
231 abort ();
232 #else
233 return 0;
234 #endif
235 }
236
237 if (dns_zone -> name)
238 dfree (dns_zone -> name, file, line);
239 if (dns_zone -> key)
240 tsig_key_dereference (&dns_zone -> key, file, line);
241 if (dns_zone -> primary)
242 option_cache_dereference (&dns_zone -> primary, file, line);
243 if (dns_zone -> secondary)
244 option_cache_dereference (&dns_zone -> secondary, file, line);
245 dfree (dns_zone, file, line);
246 return 1;
247 }
248