]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/bind9/bin/named/builtin.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.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 static dns_sdbimplementation_t *dns64_impl;
73
74 /*
75  * Pre computed HEX * 16 or 1 table.
76  */
77 static const unsigned char hex16[256] = {
78          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*00*/
79          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*10*/
80          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*20*/
81          0, 16, 32, 48, 64, 80, 96,112,128,144,  1,  1,  1,  1,  1,  1, /*30*/
82          1,160,176,192,208,224,240,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*40*/
83          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*50*/
84          1,160,176,192,208,224,240,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*60*/
85          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*70*/
86          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*80*/
87          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*90*/
88          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*A0*/
89          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*B0*/
90          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*C0*/
91          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*D0*/
92          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*E0*/
93          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1  /*F0*/
94 };
95
96 const unsigned char decimal[] = "0123456789";
97
98 static size_t
99 dns64_rdata(unsigned char *v, size_t start, unsigned char *rdata) {
100         size_t i, j = 0;
101
102         for (i = 0; i < 4U; i++) {
103                 unsigned char c = v[start++];
104                 if (start == 7U)
105                         start++;
106                 if (c > 99) {
107                         rdata[j++] = 3;
108                         rdata[j++] = decimal[c/100]; c = c % 100;
109                         rdata[j++] = decimal[c/10]; c = c % 10;
110                         rdata[j++] = decimal[c];
111                 } else if (c > 9) {
112                         rdata[j++] = 2;
113                         rdata[j++] = decimal[c/10]; c = c % 10;
114                         rdata[j++] = decimal[c];
115                 } else {
116                         rdata[j++] = 1;
117                         rdata[j++] = decimal[c];
118                 }
119         }
120         memcpy(&rdata[j], "\07in-addr\04arpa", 14);
121         return (j + 14);
122 }
123
124 static isc_result_t
125 dns64_cname(const dns_name_t *zone, const dns_name_t *name,
126             dns_sdblookup_t *lookup)
127 {
128         size_t zlen, nlen, j, len;
129         unsigned char v[16], n;
130         unsigned int i;
131         unsigned char rdata[sizeof("123.123.123.123.in-addr.arpa.")];
132         unsigned char *ndata;
133
134         /*
135          * The combined length of the zone and name is 74.
136          *
137          * The minimum zone length is 10 ((3)ip6(4)arpa(0)).
138          *
139          * The length of name should always be even as we are expecting
140          * a series of nibbles.
141          */
142         zlen = zone->length;
143         nlen = name->length;
144         if ((zlen + nlen) > 74U || zlen < 10U || (nlen % 2) != 0U)
145                 return (ISC_R_NOTFOUND);
146
147         /*
148          * We assume the zone name is well formed.
149          */
150
151         /*
152          * XXXMPA We could check the dns64 suffix here if we need to.
153          */
154         /*
155          * Check that name is a series of nibbles.
156          * Compute the byte values that correspond to the nibbles as we go.
157          *
158          * Shift the final result 4 bits, by setting 'i' to 1, if we if we
159          * have a odd number of nibbles so that "must be zero" tests below
160          * are byte aligned and we correctly return ISC_R_NOTFOUND or
161          * ISC_R_SUCCESS.  We will not generate a CNAME in this case.
162          */
163         ndata = name->ndata;
164         i = (nlen % 4) == 2U ? 1 : 0;
165         j = nlen;
166         memset(v, 0, sizeof(v));
167         while (j != 0U) {
168                 INSIST((i/2) < sizeof(v));
169                 if (ndata[0] != 1)
170                         return (ISC_R_NOTFOUND);
171                 n = hex16[ndata[1]&0xff];
172                 if (n == 1)
173                         return (ISC_R_NOTFOUND);
174                 v[i/2] = n | (v[i/2]>>4);
175                 j -= 2;
176                 ndata += 2;
177                 i++;
178         }
179
180         /*
181          * If we get here then we know name only consisted of nibbles.
182          * Now we need to determine if the name exists or not and whether
183          * it corresponds to a empty node in the zone or there should be
184          * a CNAME.
185          */
186 #define ZLEN(x) (10 + (x)/2)
187         switch (zlen) {
188         case ZLEN(32):  /* prefix len 32 */
189                 /*
190                  * The nibbles that map to this byte must be zero for 'name'
191                  * to exist in the zone.
192                  */
193                 if (nlen > 16U && v[(nlen-1)/4 - 4] != 0)
194                         return (ISC_R_NOTFOUND);
195                 /*
196                  * If the total length is not 74 then this is a empty node
197                  * so return success.
198                  */
199                 if (nlen + zlen != 74U)
200                         return (ISC_R_SUCCESS);
201                 len = dns64_rdata(v, 8, rdata);
202                 break;
203         case ZLEN(40):  /* prefix len 40 */
204                 /*
205                  * The nibbles that map to this byte must be zero for 'name'
206                  * to exist in the zone.
207                  */
208                 if (nlen > 12U && v[(nlen-1)/4 - 3] != 0)
209                         return (ISC_R_NOTFOUND);
210                 /*
211                  * If the total length is not 74 then this is a empty node
212                  * so return success.
213                  */
214                 if (nlen + zlen != 74U)
215                         return (ISC_R_SUCCESS);
216                 len = dns64_rdata(v, 6, rdata);
217                 break;
218         case ZLEN(48):  /* prefix len 48 */
219                 /*
220                  * The nibbles that map to this byte must be zero for 'name'
221                  * to exist in the zone.
222                  */
223                 if (nlen > 8U && v[(nlen-1)/4 - 2] != 0)
224                         return (ISC_R_NOTFOUND);
225                 /*
226                  * If the total length is not 74 then this is a empty node
227                  * so return success.
228                  */
229                 if (nlen + zlen != 74U)
230                         return (ISC_R_SUCCESS);
231                 len = dns64_rdata(v, 5, rdata);
232                 break;
233         case ZLEN(56):  /* prefix len 56 */
234                 /*
235                  * The nibbles that map to this byte must be zero for 'name'
236                  * to exist in the zone.
237                  */
238                 if (nlen > 4U && v[(nlen-1)/4 - 1] != 0)
239                         return (ISC_R_NOTFOUND);
240                 /*
241                  * If the total length is not 74 then this is a empty node
242                  * so return success.
243                  */
244                 if (nlen + zlen != 74U)
245                         return (ISC_R_SUCCESS);
246                 len = dns64_rdata(v, 4, rdata);
247                 break;
248         case ZLEN(64):  /* prefix len 64 */
249                 /*
250                  * The nibbles that map to this byte must be zero for 'name'
251                  * to exist in the zone.
252                  */
253                 if (v[(nlen-1)/4] != 0)
254                         return (ISC_R_NOTFOUND);
255                 /*
256                  * If the total length is not 74 then this is a empty node
257                  * so return success.
258                  */
259                 if (nlen + zlen != 74U)
260                         return (ISC_R_SUCCESS);
261                 len = dns64_rdata(v, 3, rdata);
262                 break;
263         case ZLEN(96):  /* prefix len 96 */
264                 /*
265                  * If the total length is not 74 then this is a empty node
266                  * so return success.
267                  */
268                 if (nlen + zlen != 74U)
269                         return (ISC_R_SUCCESS);
270                 len = dns64_rdata(v, 0, rdata);
271                 break;
272         default:
273                 /*
274                  * This should never be reached unless someone adds a
275                  * zone declaration with this internal type to named.conf.
276                  */
277                 return (ISC_R_NOTFOUND);
278         }
279         return (dns_sdb_putrdata(lookup, dns_rdatatype_cname, 600, rdata, len));
280 }
281
282 static isc_result_t
283 builtin_lookup(const char *zone, const char *name, void *dbdata,
284                dns_sdblookup_t *lookup)
285 {
286         builtin_t *b = (builtin_t *) dbdata;
287
288         UNUSED(zone);
289
290         if (strcmp(name, "@") == 0)
291                 return (b->do_lookup(lookup));
292         else
293                 return (ISC_R_NOTFOUND);
294 }
295
296 static isc_result_t
297 dns64_lookup(const dns_name_t *zone, const dns_name_t *name, void *dbdata,
298              dns_sdblookup_t *lookup)
299 {
300         builtin_t *b = (builtin_t *) dbdata;
301
302         if (name->labels == 0 && name->length == 0)
303                 return (b->do_lookup(lookup));
304         else
305                 return (dns64_cname(zone, name, lookup));
306 }
307
308 static isc_result_t
309 put_txt(dns_sdblookup_t *lookup, const char *text) {
310         unsigned char buf[256];
311         unsigned int len = strlen(text);
312         if (len > 255)
313                 len = 255; /* Silently truncate */
314         buf[0] = len;
315         memcpy(&buf[1], text, len);
316         return (dns_sdb_putrdata(lookup, dns_rdatatype_txt, 0, buf, len + 1));
317 }
318
319 static isc_result_t
320 do_version_lookup(dns_sdblookup_t *lookup) {
321         if (ns_g_server->version_set) {
322                 if (ns_g_server->version == NULL)
323                         return (ISC_R_SUCCESS);
324                 else
325                         return (put_txt(lookup, ns_g_server->version));
326         } else {
327                 return (put_txt(lookup, ns_g_version));
328         }
329 }
330
331 static isc_result_t
332 do_hostname_lookup(dns_sdblookup_t *lookup) {
333         if (ns_g_server->hostname_set) {
334                 if (ns_g_server->hostname == NULL)
335                         return (ISC_R_SUCCESS);
336                 else
337                         return (put_txt(lookup, ns_g_server->hostname));
338         } else {
339                 char buf[256];
340                 isc_result_t result = ns_os_gethostname(buf, sizeof(buf));
341                 if (result != ISC_R_SUCCESS)
342                         return (result);
343                 return (put_txt(lookup, buf));
344         }
345 }
346
347 static isc_result_t
348 do_authors_lookup(dns_sdblookup_t *lookup) {
349         isc_result_t result;
350         const char **p;
351         static const char *authors[] = {
352                 "Mark Andrews",
353                 "Curtis Blackburn",
354                 "James Brister",
355                 "Ben Cottrell",
356                 "Michael Graff",
357                 "Andreas Gustafsson",
358                 "Bob Halley",
359                 "Evan Hunt",
360                 "JINMEI Tatuya",
361                 "David Lawrence",
362                 "Scott Mann",
363                 "Danny Mayer",
364                 "Damien Neil",
365                 "Matt Nelson",
366                 "Jeremy C. Reed",
367                 "Michael Sawyer",
368                 "Brian Wellington",
369                 NULL
370         };
371
372         /*
373          * If a version string is specified, disable the authors.bind zone.
374          */
375         if (ns_g_server->version_set)
376                 return (ISC_R_SUCCESS);
377
378         for (p = authors; *p != NULL; p++) {
379                 result = put_txt(lookup, *p);
380                 if (result != ISC_R_SUCCESS)
381                         return (result);
382         }
383         return (ISC_R_SUCCESS);
384 }
385
386 static isc_result_t
387 do_id_lookup(dns_sdblookup_t *lookup) {
388
389         if (ns_g_server->server_usehostname) {
390                 char buf[256];
391                 isc_result_t result = ns_os_gethostname(buf, sizeof(buf));
392                 if (result != ISC_R_SUCCESS)
393                         return (result);
394                 return (put_txt(lookup, buf));
395         }
396
397         if (ns_g_server->server_id == NULL)
398                 return (ISC_R_SUCCESS);
399         else
400                 return (put_txt(lookup, ns_g_server->server_id));
401 }
402
403 static isc_result_t
404 do_dns64_lookup(dns_sdblookup_t *lookup) {
405         UNUSED(lookup);
406         return (ISC_R_SUCCESS);
407 }
408
409 static isc_result_t
410 do_empty_lookup(dns_sdblookup_t *lookup) {
411
412         UNUSED(lookup);
413         return (ISC_R_SUCCESS);
414 }
415
416 static isc_result_t
417 builtin_authority(const char *zone, void *dbdata, dns_sdblookup_t *lookup) {
418         isc_result_t result;
419         const char *contact = "hostmaster";
420         const char *server = "@";
421         builtin_t *b = (builtin_t *) dbdata;
422
423         UNUSED(zone);
424         UNUSED(dbdata);
425
426         if (b == &empty_builtin) {
427                 server = ".";
428                 contact = ".";
429         } else {
430                 if (b->server != NULL)
431                         server = b->server;
432                 if (b->contact != NULL)
433                         contact = b->contact;
434         }
435
436         result = dns_sdb_putsoa(lookup, server, contact, 0);
437         if (result != ISC_R_SUCCESS)
438                 return (ISC_R_FAILURE);
439
440         result = dns_sdb_putrr(lookup, "ns", 0, server);
441         if (result != ISC_R_SUCCESS)
442                 return (ISC_R_FAILURE);
443
444         return (ISC_R_SUCCESS);
445 }
446
447 static isc_result_t
448 builtin_create(const char *zone, int argc, char **argv,
449                void *driverdata, void **dbdata)
450 {
451         REQUIRE(argc >= 1);
452
453         UNUSED(zone);
454         UNUSED(driverdata);
455
456         if (strcmp(argv[0], "empty") == 0 || strcmp(argv[0], "dns64") == 0) {
457                 if (argc != 3)
458                         return (DNS_R_SYNTAX);
459         } else if (argc != 1)
460                 return (DNS_R_SYNTAX);
461
462         if (strcmp(argv[0], "version") == 0)
463                 *dbdata = &version_builtin;
464         else if (strcmp(argv[0], "hostname") == 0)
465                 *dbdata = &hostname_builtin;
466         else if (strcmp(argv[0], "authors") == 0)
467                 *dbdata = &authors_builtin;
468         else if (strcmp(argv[0], "id") == 0)
469                 *dbdata = &id_builtin;
470         else if (strcmp(argv[0], "empty") == 0 ||
471                  strcmp(argv[0], "dns64") == 0) {
472                 builtin_t *empty;
473                 char *server;
474                 char *contact;
475                 /*
476                  * We don't want built-in zones to fail.  Fallback to
477                  * the static configuration if memory allocation fails.
478                  */
479                 empty = isc_mem_get(ns_g_mctx, sizeof(*empty));
480                 server = isc_mem_strdup(ns_g_mctx, argv[1]);
481                 contact = isc_mem_strdup(ns_g_mctx, argv[2]);
482                 if (empty == NULL || server == NULL || contact == NULL) {
483                         if (strcmp(argv[0], "empty") == 0)
484                                 *dbdata = &empty_builtin;
485                         else
486                                 *dbdata = &dns64_builtin;
487                         if (server != NULL)
488                                 isc_mem_free(ns_g_mctx, server);
489                         if (contact != NULL)
490                                 isc_mem_free(ns_g_mctx, contact);
491                         if (empty != NULL)
492                                 isc_mem_put(ns_g_mctx, empty, sizeof (*empty));
493                 } else {
494                         if (strcmp(argv[0], "empty") == 0)
495                                 memcpy(empty, &empty_builtin,
496                                        sizeof (empty_builtin));
497                         else
498                                 memcpy(empty, &dns64_builtin,
499                                        sizeof (empty_builtin));
500                         empty->server = server;
501                         empty->contact = contact;
502                         *dbdata = empty;
503                 }
504         } else
505                 return (ISC_R_NOTIMPLEMENTED);
506         return (ISC_R_SUCCESS);
507 }
508
509 static void
510 builtin_destroy(const char *zone, void *driverdata, void **dbdata) {
511         builtin_t *b = (builtin_t *) *dbdata;
512
513         UNUSED(zone);
514         UNUSED(driverdata);
515
516         /*
517          * Don't free the static versions.
518          */
519         if (*dbdata == &version_builtin || *dbdata == &hostname_builtin ||
520             *dbdata == &authors_builtin || *dbdata == &id_builtin ||
521             *dbdata == &empty_builtin || *dbdata == &dns64_builtin)
522                 return;
523
524         isc_mem_free(ns_g_mctx, b->server);
525         isc_mem_free(ns_g_mctx, b->contact);
526         isc_mem_put(ns_g_mctx, b, sizeof (*b));
527 }
528
529 static dns_sdbmethods_t builtin_methods = {
530         builtin_lookup,
531         builtin_authority,
532         NULL,           /* allnodes */
533         builtin_create,
534         builtin_destroy,
535         NULL
536 };
537
538 static dns_sdbmethods_t dns64_methods = {
539         NULL,
540         builtin_authority,
541         NULL,           /* allnodes */
542         builtin_create,
543         builtin_destroy,
544         dns64_lookup,
545 };
546
547 isc_result_t
548 ns_builtin_init(void) {
549         RUNTIME_CHECK(dns_sdb_register("_builtin", &builtin_methods, NULL,
550                                        DNS_SDBFLAG_RELATIVEOWNER |
551                                        DNS_SDBFLAG_RELATIVERDATA,
552                                        ns_g_mctx, &builtin_impl)
553                       == ISC_R_SUCCESS);
554         RUNTIME_CHECK(dns_sdb_register("_dns64", &dns64_methods, NULL,
555                                        DNS_SDBFLAG_RELATIVEOWNER |
556                                        DNS_SDBFLAG_RELATIVERDATA |
557                                        DNS_SDBFLAG_DNS64,
558                                        ns_g_mctx, &dns64_impl)
559                       == ISC_R_SUCCESS);
560         return (ISC_R_SUCCESS);
561 }
562
563 void
564 ns_builtin_deinit(void) {
565         dns_sdb_unregister(&builtin_impl);
566         dns_sdb_unregister(&dns64_impl);
567 }