]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bind9/bin/named/builtin.c
Update to version 9.8.2, the latest from ISC, which contains numerous bug fixes.
[FreeBSD/FreeBSD.git] / contrib / bind9 / bin / named / builtin.c
1 /*
2  * Copyright (C) 2004, 2005, 2007, 2009-2012  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2001-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id: builtin.c,v 1.20.14.3 2012/01/11 20:19:40 ckb Exp $ */
19
20 /*! \file
21  * \brief
22  * The built-in "version", "hostname", "id", "authors" and "empty" databases.
23  */
24
25 #include <config.h>
26
27 #include <string.h>
28 #include <stdio.h>
29
30 #include <isc/mem.h>
31 #include <isc/print.h>
32 #include <isc/result.h>
33 #include <isc/util.h>
34
35 #include <dns/result.h>
36 #include <dns/sdb.h>
37
38 #include <named/builtin.h>
39 #include <named/globals.h>
40 #include <named/server.h>
41 #include <named/os.h>
42
43 typedef struct builtin builtin_t;
44
45 static isc_result_t do_version_lookup(dns_sdblookup_t *lookup);
46 static isc_result_t do_hostname_lookup(dns_sdblookup_t *lookup);
47 static isc_result_t do_authors_lookup(dns_sdblookup_t *lookup);
48 static isc_result_t do_id_lookup(dns_sdblookup_t *lookup);
49 static isc_result_t do_empty_lookup(dns_sdblookup_t *lookup);
50 static isc_result_t do_dns64_lookup(dns_sdblookup_t *lookup);
51
52 /*
53  * We can't use function pointers as the db_data directly
54  * because ANSI C does not guarantee that function pointers
55  * can safely be cast to void pointers and back.
56  */
57
58 struct builtin {
59         isc_result_t (*do_lookup)(dns_sdblookup_t *lookup);
60         char *server;
61         char *contact;
62 };
63
64 static builtin_t version_builtin = { do_version_lookup,  NULL, NULL };
65 static builtin_t hostname_builtin = { do_hostname_lookup, NULL, NULL };
66 static builtin_t authors_builtin = { do_authors_lookup, NULL, NULL };
67 static builtin_t id_builtin = { do_id_lookup, NULL, NULL };
68 static builtin_t empty_builtin = { do_empty_lookup, NULL, NULL };
69 static builtin_t dns64_builtin = { do_dns64_lookup, NULL, NULL };
70
71 static dns_sdbimplementation_t *builtin_impl;
72
73 static const char hex[] = "0123456789abcdef";
74 static const char HEX[] = "0123456789ABCDEF";
75
76 static isc_result_t
77 dns64_cname(const char *zone, const char *name, dns_sdblookup_t *lookup) {
78         size_t zlen, nlen, j;
79         const char *s;
80         unsigned char v[16];
81         unsigned int i;
82         char reverse[sizeof("123.123.123.123.in-addr.arpa.")];
83
84         /*
85          * The sum the length of the relative name and the length of the zone
86          * name for a IPv6 reverse lookup comes to 71.
87          *
88          * The reverse of 2001::10.0.0.1 (dns64 2001::/96) has a zone of
89          * "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.2.ip6.arpa"
90          * and a name of "1.0.0.0.0.0.a.0".  The sum of the lengths of these
91          * two strings is 71.
92          *
93          * The minimum length for a ip6.arpa zone name is 8.
94          *
95          * The length of name should always be odd as we are expecting
96          * a series of nibbles.
97          */
98         zlen = strlen(zone);
99         nlen = strlen(name);
100         if ((zlen + nlen) > 71U || zlen < 8U || (nlen % 2) != 1U)
101                 return (ISC_R_NOTFOUND);
102
103         /*
104          * We assume the zone name is well formed.
105          */
106
107         /*
108          * XXXMPA We could check the dns64 suffix here if we need to.
109          */
110         /*
111          * Check that name is a series of nibbles.
112          * Compute the byte values that correspond to the nibbles as we go.
113          *
114          * Shift the final result 4 bits, by setting 'i' to 1, if we if we
115          * have a odd number of nibbles so that "must be zero" tests below
116          * are byte aligned and we correctly return ISC_R_NOTFOUND or
117          * ISC_R_SUCCESS.  We will not generate a CNAME in this case.
118          */
119         i = (nlen % 4) == 1U ? 1 : 0;
120         j = nlen;
121         memset(v, 0, sizeof(v));
122         while (j >= 1U) {
123                 INSIST((i/2) < sizeof(v));
124                 if (j > 1U && name[1] != '.')
125                         return (ISC_R_NOTFOUND);
126                 v[i/2] >>= 4;
127                 if ((s = strchr(hex, name[0])) != NULL)
128                         v[i/2] |= (s - hex) << 4;
129                 else if ((s = strchr(HEX, name[0])) != NULL)
130                         v[i/2] |= (s - HEX) << 4;
131                 else
132                         return (ISC_R_NOTFOUND);
133                 if (j > 1U)
134                         j -= 2;
135                 else
136                         j -= 1;
137                 name += 2;
138                 i++;
139         }
140
141         /*
142          * If we get here then we know name only consisted of nibbles.
143          * Now we need to determine if the name exists or not and whether
144          * it corresponds to a empty node in the zone or there should be
145          * a CNAME.
146          */
147         switch (zlen) {
148         case 24:        /* prefix len 32 */
149                 /*
150                  * If the total length is not 71 then this is a empty node
151                  * so return success.
152                  */
153                 if (nlen + zlen != 71U)
154                         return (ISC_R_SUCCESS);
155                 snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.",
156                          v[8], v[9], v[10], v[11]);
157                 break;
158         case 28:        /* prefix len 40 */
159                 /*
160                  * The nibbles that map to this byte must be zero for 'name'
161                  * to exist in the zone.
162                  */
163                 if (nlen > 11U && v[nlen/4 - 3] != 0)
164                         return (ISC_R_NOTFOUND);
165                 /*
166                  * If the total length is not 71 then this is a empty node
167                  * so return success.
168                  */
169                 if (nlen + zlen != 71U)
170                         return (ISC_R_SUCCESS);
171                 snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.",
172                          v[6], v[8], v[9], v[10]);
173                 break;
174         case 32:        /* prefix len 48 */
175                 /*
176                  * The nibbles that map to this byte must be zero for 'name'
177                  * to exist in the zone.
178                  */
179                 if (nlen > 7U && v[nlen/4 - 2] != 0)
180                         return (ISC_R_NOTFOUND);
181                 /*
182                  * If the total length is not 71 then this is a empty node
183                  * so return success.
184                  */
185                 if (nlen + zlen != 71U)
186                         return (ISC_R_SUCCESS);
187                 snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.",
188                          v[5], v[6], v[8], v[9]);
189                 break;
190         case 36:        /* prefix len 56 */
191                 /*
192                  * The nibbles that map to this byte must be zero for 'name'
193                  * to exist in the zone.
194                  */
195                 if (nlen > 3U && v[nlen/4 - 1] != 0)
196                         return (ISC_R_NOTFOUND);
197                 /*
198                  * If the total length is not 71 then this is a empty node
199                  * so return success.
200                  */
201                 if (nlen + zlen != 71U)
202                         return (ISC_R_SUCCESS);
203                 snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.",
204                          v[4], v[5], v[6], v[8]);
205                 break;
206         case 40:        /* prefix len 64 */
207                 /*
208                  * The nibbles that map to this byte must be zero for 'name'
209                  * to exist in the zone.
210                  */
211                 if (v[nlen/4] != 0)
212                         return (ISC_R_NOTFOUND);
213                 /*
214                  * If the total length is not 71 then this is a empty node
215                  * so return success.
216                  */
217                 if (nlen + zlen != 71U)
218                         return (ISC_R_SUCCESS);
219                 snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.",
220                          v[3], v[4], v[5], v[6]);
221                 break;
222         case 56:        /* prefix len 96 */
223                 /*
224                  * If the total length is not 71 then this is a empty node
225                  * so return success.
226                  */
227                 if (nlen + zlen != 71U)
228                         return (ISC_R_SUCCESS);
229                 snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.",
230                          v[0], v[1], v[2], v[3]);
231                 break;
232         default:
233                 /*
234                  * This should never be reached unless someone adds a
235                  * zone declaration with this internal type to named.conf.
236                  */
237                 return (ISC_R_NOTFOUND);
238         }
239         return (dns_sdb_putrr(lookup, "CNAME", 600, reverse));
240 }
241
242 static isc_result_t
243 builtin_lookup(const char *zone, const char *name, void *dbdata,
244                dns_sdblookup_t *lookup)
245 {
246         builtin_t *b = (builtin_t *) dbdata;
247
248         UNUSED(zone);
249
250         if (strcmp(name, "@") == 0)
251                 return (b->do_lookup(lookup));
252         else if (b->do_lookup == do_dns64_lookup)
253                 return (dns64_cname(zone, name, lookup));
254         else
255                 return (ISC_R_NOTFOUND);
256 }
257
258 static isc_result_t
259 put_txt(dns_sdblookup_t *lookup, const char *text) {
260         unsigned char buf[256];
261         unsigned int len = strlen(text);
262         if (len > 255)
263                 len = 255; /* Silently truncate */
264         buf[0] = len;
265         memcpy(&buf[1], text, len);
266         return (dns_sdb_putrdata(lookup, dns_rdatatype_txt, 0, buf, len + 1));
267 }
268
269 static isc_result_t
270 do_version_lookup(dns_sdblookup_t *lookup) {
271         if (ns_g_server->version_set) {
272                 if (ns_g_server->version == NULL)
273                         return (ISC_R_SUCCESS);
274                 else
275                         return (put_txt(lookup, ns_g_server->version));
276         } else {
277                 return (put_txt(lookup, ns_g_version));
278         }
279 }
280
281 static isc_result_t
282 do_hostname_lookup(dns_sdblookup_t *lookup) {
283         if (ns_g_server->hostname_set) {
284                 if (ns_g_server->hostname == NULL)
285                         return (ISC_R_SUCCESS);
286                 else
287                         return (put_txt(lookup, ns_g_server->hostname));
288         } else {
289                 char buf[256];
290                 isc_result_t result = ns_os_gethostname(buf, sizeof(buf));
291                 if (result != ISC_R_SUCCESS)
292                         return (result);
293                 return (put_txt(lookup, buf));
294         }
295 }
296
297 static isc_result_t
298 do_authors_lookup(dns_sdblookup_t *lookup) {
299         isc_result_t result;
300         const char **p;
301         static const char *authors[] = {
302                 "Mark Andrews",
303                 "Curtis Blackburn",
304                 "James Brister",
305                 "Ben Cottrell",
306                 "Michael Graff",
307                 "Andreas Gustafsson",
308                 "Bob Halley",
309                 "Evan Hunt",
310                 "JINMEI Tatuya",
311                 "David Lawrence",
312                 "Scott Mann",
313                 "Danny Mayer",
314                 "Damien Neil",
315                 "Matt Nelson",
316                 "Jeremy C. Reed",
317                 "Michael Sawyer",
318                 "Brian Wellington",
319                 NULL
320         };
321
322         /*
323          * If a version string is specified, disable the authors.bind zone.
324          */
325         if (ns_g_server->version_set)
326                 return (ISC_R_SUCCESS);
327
328         for (p = authors; *p != NULL; p++) {
329                 result = put_txt(lookup, *p);
330                 if (result != ISC_R_SUCCESS)
331                         return (result);
332         }
333         return (ISC_R_SUCCESS);
334 }
335
336 static isc_result_t
337 do_id_lookup(dns_sdblookup_t *lookup) {
338
339         if (ns_g_server->server_usehostname) {
340                 char buf[256];
341                 isc_result_t result = ns_os_gethostname(buf, sizeof(buf));
342                 if (result != ISC_R_SUCCESS)
343                         return (result);
344                 return (put_txt(lookup, buf));
345         }
346
347         if (ns_g_server->server_id == NULL)
348                 return (ISC_R_SUCCESS);
349         else
350                 return (put_txt(lookup, ns_g_server->server_id));
351 }
352
353 static isc_result_t
354 do_dns64_lookup(dns_sdblookup_t *lookup) {
355         UNUSED(lookup);
356         return (ISC_R_SUCCESS);
357 }
358
359 static isc_result_t
360 do_empty_lookup(dns_sdblookup_t *lookup) {
361
362         UNUSED(lookup);
363         return (ISC_R_SUCCESS);
364 }
365
366 static isc_result_t
367 builtin_authority(const char *zone, void *dbdata, dns_sdblookup_t *lookup) {
368         isc_result_t result;
369         const char *contact = "hostmaster";
370         const char *server = "@";
371         builtin_t *b = (builtin_t *) dbdata;
372
373         UNUSED(zone);
374         UNUSED(dbdata);
375
376         if (b == &empty_builtin) {
377                 server = ".";
378                 contact = ".";
379         } else {
380                 if (b->server != NULL)
381                         server = b->server;
382                 if (b->contact != NULL)
383                         contact = b->contact;
384         }
385
386         result = dns_sdb_putsoa(lookup, server, contact, 0);
387         if (result != ISC_R_SUCCESS)
388                 return (ISC_R_FAILURE);
389
390         result = dns_sdb_putrr(lookup, "ns", 0, server);
391         if (result != ISC_R_SUCCESS)
392                 return (ISC_R_FAILURE);
393
394         return (ISC_R_SUCCESS);
395 }
396
397 static isc_result_t
398 builtin_create(const char *zone, int argc, char **argv,
399                void *driverdata, void **dbdata)
400 {
401         REQUIRE(argc >= 1);
402
403         UNUSED(zone);
404         UNUSED(driverdata);
405
406         if (strcmp(argv[0], "empty") == 0 || strcmp(argv[0], "dns64") == 0) {
407                 if (argc != 3)
408                         return (DNS_R_SYNTAX);
409         } else if (argc != 1)
410                 return (DNS_R_SYNTAX);
411
412         if (strcmp(argv[0], "version") == 0)
413                 *dbdata = &version_builtin;
414         else if (strcmp(argv[0], "hostname") == 0)
415                 *dbdata = &hostname_builtin;
416         else if (strcmp(argv[0], "authors") == 0)
417                 *dbdata = &authors_builtin;
418         else if (strcmp(argv[0], "id") == 0)
419                 *dbdata = &id_builtin;
420         else if (strcmp(argv[0], "empty") == 0 ||
421                  strcmp(argv[0], "dns64") == 0) {
422                 builtin_t *empty;
423                 char *server;
424                 char *contact;
425                 /*
426                  * We don't want built-in zones to fail.  Fallback to
427                  * the static configuration if memory allocation fails.
428                  */
429                 empty = isc_mem_get(ns_g_mctx, sizeof(*empty));
430                 server = isc_mem_strdup(ns_g_mctx, argv[1]);
431                 contact = isc_mem_strdup(ns_g_mctx, argv[2]);
432                 if (empty == NULL || server == NULL || contact == NULL) {
433                         if (strcmp(argv[0], "empty") == 0)
434                                 *dbdata = &empty_builtin;
435                         else
436                                 *dbdata = &dns64_builtin;
437                         if (server != NULL)
438                                 isc_mem_free(ns_g_mctx, server);
439                         if (contact != NULL)
440                                 isc_mem_free(ns_g_mctx, contact);
441                         if (empty != NULL)
442                                 isc_mem_put(ns_g_mctx, empty, sizeof (*empty));
443                 } else {
444                         if (strcmp(argv[0], "empty") == 0)
445                                 memcpy(empty, &empty_builtin,
446                                        sizeof (empty_builtin));
447                         else
448                                 memcpy(empty, &dns64_builtin,
449                                        sizeof (empty_builtin));
450                         empty->server = server;
451                         empty->contact = contact;
452                         *dbdata = empty;
453                 }
454         } else
455                 return (ISC_R_NOTIMPLEMENTED);
456         return (ISC_R_SUCCESS);
457 }
458
459 static void
460 builtin_destroy(const char *zone, void *driverdata, void **dbdata) {
461         builtin_t *b = (builtin_t *) *dbdata;
462
463         UNUSED(zone);
464         UNUSED(driverdata);
465
466         /*
467          * Don't free the static versions.
468          */
469         if (*dbdata == &version_builtin || *dbdata == &hostname_builtin ||
470             *dbdata == &authors_builtin || *dbdata == &id_builtin ||
471             *dbdata == &empty_builtin || *dbdata == &dns64_builtin)
472                 return;
473
474         isc_mem_free(ns_g_mctx, b->server);
475         isc_mem_free(ns_g_mctx, b->contact);
476         isc_mem_put(ns_g_mctx, b, sizeof (*b));
477 }
478
479 static dns_sdbmethods_t builtin_methods = {
480         builtin_lookup,
481         builtin_authority,
482         NULL,           /* allnodes */
483         builtin_create,
484         builtin_destroy
485 };
486
487 isc_result_t
488 ns_builtin_init(void) {
489         RUNTIME_CHECK(dns_sdb_register("_builtin", &builtin_methods, NULL,
490                                        DNS_SDBFLAG_RELATIVEOWNER |
491                                        DNS_SDBFLAG_RELATIVERDATA,
492                                        ns_g_mctx, &builtin_impl)
493                       == ISC_R_SUCCESS);
494         return (ISC_R_SUCCESS);
495 }
496
497 void
498 ns_builtin_deinit(void) {
499         dns_sdb_unregister(&builtin_impl);
500 }
501