]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - contrib/bind9/bin/named/builtin.c
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / contrib / bind9 / bin / named / builtin.c
1 /*
2  * Copyright (C) 2004, 2005, 2007, 2009-2011  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 2011-01-07 23:47:07 tbox 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                 "James Brister",
304                 "Ben Cottrell",
305                 "Michael Graff",
306                 "Andreas Gustafsson",
307                 "Bob Halley",
308                 "Evan Hunt",
309                 "JINMEI Tatuya",
310                 "David Lawrence",
311                 "Danny Mayer",
312                 "Damien Neil",
313                 "Matt Nelson",
314                 "Jeremy C. Reed",
315                 "Michael Sawyer",
316                 "Brian Wellington",
317                 NULL
318         };
319
320         /*
321          * If a version string is specified, disable the authors.bind zone.
322          */
323         if (ns_g_server->version_set)
324                 return (ISC_R_SUCCESS);
325
326         for (p = authors; *p != NULL; p++) {
327                 result = put_txt(lookup, *p);
328                 if (result != ISC_R_SUCCESS)
329                         return (result);
330         }
331         return (ISC_R_SUCCESS);
332 }
333
334 static isc_result_t
335 do_id_lookup(dns_sdblookup_t *lookup) {
336
337         if (ns_g_server->server_usehostname) {
338                 char buf[256];
339                 isc_result_t result = ns_os_gethostname(buf, sizeof(buf));
340                 if (result != ISC_R_SUCCESS)
341                         return (result);
342                 return (put_txt(lookup, buf));
343         }
344
345         if (ns_g_server->server_id == NULL)
346                 return (ISC_R_SUCCESS);
347         else
348                 return (put_txt(lookup, ns_g_server->server_id));
349 }
350
351 static isc_result_t
352 do_dns64_lookup(dns_sdblookup_t *lookup) {
353         UNUSED(lookup);
354         return (ISC_R_SUCCESS);
355 }
356
357 static isc_result_t
358 do_empty_lookup(dns_sdblookup_t *lookup) {
359
360         UNUSED(lookup);
361         return (ISC_R_SUCCESS);
362 }
363
364 static isc_result_t
365 builtin_authority(const char *zone, void *dbdata, dns_sdblookup_t *lookup) {
366         isc_result_t result;
367         const char *contact = "hostmaster";
368         const char *server = "@";
369         builtin_t *b = (builtin_t *) dbdata;
370
371         UNUSED(zone);
372         UNUSED(dbdata);
373
374         if (b == &empty_builtin) {
375                 server = ".";
376                 contact = ".";
377         } else {
378                 if (b->server != NULL)
379                         server = b->server;
380                 if (b->contact != NULL)
381                         contact = b->contact;
382         }
383
384         result = dns_sdb_putsoa(lookup, server, contact, 0);
385         if (result != ISC_R_SUCCESS)
386                 return (ISC_R_FAILURE);
387
388         result = dns_sdb_putrr(lookup, "ns", 0, server);
389         if (result != ISC_R_SUCCESS)
390                 return (ISC_R_FAILURE);
391
392         return (ISC_R_SUCCESS);
393 }
394
395 static isc_result_t
396 builtin_create(const char *zone, int argc, char **argv,
397                void *driverdata, void **dbdata)
398 {
399         REQUIRE(argc >= 1);
400
401         UNUSED(zone);
402         UNUSED(driverdata);
403
404         if (strcmp(argv[0], "empty") == 0 || strcmp(argv[0], "dns64") == 0) {
405                 if (argc != 3)
406                         return (DNS_R_SYNTAX);
407         } else if (argc != 1)
408                 return (DNS_R_SYNTAX);
409
410         if (strcmp(argv[0], "version") == 0)
411                 *dbdata = &version_builtin;
412         else if (strcmp(argv[0], "hostname") == 0)
413                 *dbdata = &hostname_builtin;
414         else if (strcmp(argv[0], "authors") == 0)
415                 *dbdata = &authors_builtin;
416         else if (strcmp(argv[0], "id") == 0)
417                 *dbdata = &id_builtin;
418         else if (strcmp(argv[0], "empty") == 0 ||
419                  strcmp(argv[0], "dns64") == 0) {
420                 builtin_t *empty;
421                 char *server;
422                 char *contact;
423                 /*
424                  * We don't want built-in zones to fail.  Fallback to
425                  * the static configuration if memory allocation fails.
426                  */
427                 empty = isc_mem_get(ns_g_mctx, sizeof(*empty));
428                 server = isc_mem_strdup(ns_g_mctx, argv[1]);
429                 contact = isc_mem_strdup(ns_g_mctx, argv[2]);
430                 if (empty == NULL || server == NULL || contact == NULL) {
431                         if (strcmp(argv[0], "empty") == 0)
432                                 *dbdata = &empty_builtin;
433                         else
434                                 *dbdata = &dns64_builtin;
435                         if (server != NULL)
436                                 isc_mem_free(ns_g_mctx, server);
437                         if (contact != NULL)
438                                 isc_mem_free(ns_g_mctx, contact);
439                         if (empty != NULL)
440                                 isc_mem_put(ns_g_mctx, empty, sizeof (*empty));
441                 } else {
442                         if (strcmp(argv[0], "empty") == 0)
443                                 memcpy(empty, &empty_builtin,
444                                        sizeof (empty_builtin));
445                         else
446                                 memcpy(empty, &dns64_builtin,
447                                        sizeof (empty_builtin));
448                         empty->server = server;
449                         empty->contact = contact;
450                         *dbdata = empty;
451                 }
452         } else
453                 return (ISC_R_NOTIMPLEMENTED);
454         return (ISC_R_SUCCESS);
455 }
456
457 static void
458 builtin_destroy(const char *zone, void *driverdata, void **dbdata) {
459         builtin_t *b = (builtin_t *) *dbdata;
460
461         UNUSED(zone);
462         UNUSED(driverdata);
463
464         /*
465          * Don't free the static versions.
466          */
467         if (*dbdata == &version_builtin || *dbdata == &hostname_builtin ||
468             *dbdata == &authors_builtin || *dbdata == &id_builtin ||
469             *dbdata == &empty_builtin || *dbdata == &dns64_builtin)
470                 return;
471
472         isc_mem_free(ns_g_mctx, b->server);
473         isc_mem_free(ns_g_mctx, b->contact);
474         isc_mem_put(ns_g_mctx, b, sizeof (*b));
475 }
476
477 static dns_sdbmethods_t builtin_methods = {
478         builtin_lookup,
479         builtin_authority,
480         NULL,           /* allnodes */
481         builtin_create,
482         builtin_destroy
483 };
484
485 isc_result_t
486 ns_builtin_init(void) {
487         RUNTIME_CHECK(dns_sdb_register("_builtin", &builtin_methods, NULL,
488                                        DNS_SDBFLAG_RELATIVEOWNER |
489                                        DNS_SDBFLAG_RELATIVERDATA,
490                                        ns_g_mctx, &builtin_impl)
491                       == ISC_R_SUCCESS);
492         return (ISC_R_SUCCESS);
493 }
494
495 void
496 ns_builtin_deinit(void) {
497         dns_sdb_unregister(&builtin_impl);
498 }
499