]> CyberLeo.Net >> Repos - FreeBSD/releng/9.3.git/blob - contrib/bind9/bin/named/builtin.c
Copy stable/9 to releng/9.3 as part of the 9.3-RELEASE cycle.
[FreeBSD/releng/9.3.git] / contrib / bind9 / bin / named / builtin.c
1 /*
2  * Copyright (C) 2004, 2005, 2007, 2009-2014  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.26 2012/01/21 19:44:18 each 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         memmove(&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,
280                                  rdata, (unsigned int)len));
281 }
282
283 static isc_result_t
284 builtin_lookup(const char *zone, const char *name, void *dbdata,
285                dns_sdblookup_t *lookup, dns_clientinfomethods_t *methods,
286                dns_clientinfo_t *clientinfo)
287 {
288         builtin_t *b = (builtin_t *) dbdata;
289
290         UNUSED(zone);
291         UNUSED(methods);
292         UNUSED(clientinfo);
293
294         if (strcmp(name, "@") == 0)
295                 return (b->do_lookup(lookup));
296         else
297                 return (ISC_R_NOTFOUND);
298 }
299
300 static isc_result_t
301 dns64_lookup(const dns_name_t *zone, const dns_name_t *name, void *dbdata,
302              dns_sdblookup_t *lookup, dns_clientinfomethods_t *methods,
303              dns_clientinfo_t *clientinfo)
304 {
305         builtin_t *b = (builtin_t *) dbdata;
306
307         UNUSED(methods);
308         UNUSED(clientinfo);
309
310         if (name->labels == 0 && name->length == 0)
311                 return (b->do_lookup(lookup));
312         else
313                 return (dns64_cname(zone, name, lookup));
314 }
315
316 static isc_result_t
317 put_txt(dns_sdblookup_t *lookup, const char *text) {
318         unsigned char buf[256];
319         unsigned int len = strlen(text);
320         if (len > 255)
321                 len = 255; /* Silently truncate */
322         buf[0] = len;
323         memmove(&buf[1], text, len);
324         return (dns_sdb_putrdata(lookup, dns_rdatatype_txt, 0, buf, len + 1));
325 }
326
327 static isc_result_t
328 do_version_lookup(dns_sdblookup_t *lookup) {
329         if (ns_g_server->version_set) {
330                 if (ns_g_server->version == NULL)
331                         return (ISC_R_SUCCESS);
332                 else
333                         return (put_txt(lookup, ns_g_server->version));
334         } else {
335                 return (put_txt(lookup, ns_g_version));
336         }
337 }
338
339 static isc_result_t
340 do_hostname_lookup(dns_sdblookup_t *lookup) {
341         if (ns_g_server->hostname_set) {
342                 if (ns_g_server->hostname == NULL)
343                         return (ISC_R_SUCCESS);
344                 else
345                         return (put_txt(lookup, ns_g_server->hostname));
346         } else {
347                 char buf[256];
348                 isc_result_t result = ns_os_gethostname(buf, sizeof(buf));
349                 if (result != ISC_R_SUCCESS)
350                         return (result);
351                 return (put_txt(lookup, buf));
352         }
353 }
354
355 static isc_result_t
356 do_authors_lookup(dns_sdblookup_t *lookup) {
357         isc_result_t result;
358         const char **p;
359         static const char *authors[] = {
360                 "Mark Andrews",
361                 "Curtis Blackburn",
362                 "James Brister",
363                 "Ben Cottrell",
364                 "John H. DuBois III",
365                 "Francis Dupont",
366                 "Michael Graff",
367                 "Andreas Gustafsson",
368                 "Bob Halley",
369                 "Evan Hunt",
370                 "JINMEI Tatuya",
371                 "David Lawrence",
372                 "Scott Mann",
373                 "Danny Mayer",
374                 "Damien Neil",
375                 "Matt Nelson",
376                 "Jeremy C. Reed",
377                 "Michael Sawyer",
378                 "Brian Wellington",
379                 NULL
380         };
381
382         /*
383          * If a version string is specified, disable the authors.bind zone.
384          */
385         if (ns_g_server->version_set)
386                 return (ISC_R_SUCCESS);
387
388         for (p = authors; *p != NULL; p++) {
389                 result = put_txt(lookup, *p);
390                 if (result != ISC_R_SUCCESS)
391                         return (result);
392         }
393         return (ISC_R_SUCCESS);
394 }
395
396 static isc_result_t
397 do_id_lookup(dns_sdblookup_t *lookup) {
398
399         if (ns_g_server->server_usehostname) {
400                 char buf[256];
401                 isc_result_t result = ns_os_gethostname(buf, sizeof(buf));
402                 if (result != ISC_R_SUCCESS)
403                         return (result);
404                 return (put_txt(lookup, buf));
405         }
406
407         if (ns_g_server->server_id == NULL)
408                 return (ISC_R_SUCCESS);
409         else
410                 return (put_txt(lookup, ns_g_server->server_id));
411 }
412
413 static isc_result_t
414 do_dns64_lookup(dns_sdblookup_t *lookup) {
415         UNUSED(lookup);
416         return (ISC_R_SUCCESS);
417 }
418
419 static isc_result_t
420 do_empty_lookup(dns_sdblookup_t *lookup) {
421
422         UNUSED(lookup);
423         return (ISC_R_SUCCESS);
424 }
425
426 static isc_result_t
427 builtin_authority(const char *zone, void *dbdata, dns_sdblookup_t *lookup) {
428         isc_result_t result;
429         const char *contact = "hostmaster";
430         const char *server = "@";
431         builtin_t *b = (builtin_t *) dbdata;
432
433         UNUSED(zone);
434         UNUSED(dbdata);
435
436         if (b == &empty_builtin) {
437                 server = ".";
438                 contact = ".";
439         } else {
440                 if (b->server != NULL)
441                         server = b->server;
442                 if (b->contact != NULL)
443                         contact = b->contact;
444         }
445
446         result = dns_sdb_putsoa(lookup, server, contact, 0);
447         if (result != ISC_R_SUCCESS)
448                 return (ISC_R_FAILURE);
449
450         result = dns_sdb_putrr(lookup, "ns", 0, server);
451         if (result != ISC_R_SUCCESS)
452                 return (ISC_R_FAILURE);
453
454         return (ISC_R_SUCCESS);
455 }
456
457 static isc_result_t
458 builtin_create(const char *zone, int argc, char **argv,
459                void *driverdata, void **dbdata)
460 {
461         REQUIRE(argc >= 1);
462
463         UNUSED(zone);
464         UNUSED(driverdata);
465
466         if (strcmp(argv[0], "empty") == 0 || strcmp(argv[0], "dns64") == 0) {
467                 if (argc != 3)
468                         return (DNS_R_SYNTAX);
469         } else if (argc != 1)
470                 return (DNS_R_SYNTAX);
471
472         if (strcmp(argv[0], "version") == 0)
473                 *dbdata = &version_builtin;
474         else if (strcmp(argv[0], "hostname") == 0)
475                 *dbdata = &hostname_builtin;
476         else if (strcmp(argv[0], "authors") == 0)
477                 *dbdata = &authors_builtin;
478         else if (strcmp(argv[0], "id") == 0)
479                 *dbdata = &id_builtin;
480         else if (strcmp(argv[0], "empty") == 0 ||
481                  strcmp(argv[0], "dns64") == 0) {
482                 builtin_t *empty;
483                 char *server;
484                 char *contact;
485                 /*
486                  * We don't want built-in zones to fail.  Fallback to
487                  * the static configuration if memory allocation fails.
488                  */
489                 empty = isc_mem_get(ns_g_mctx, sizeof(*empty));
490                 server = isc_mem_strdup(ns_g_mctx, argv[1]);
491                 contact = isc_mem_strdup(ns_g_mctx, argv[2]);
492                 if (empty == NULL || server == NULL || contact == NULL) {
493                         if (strcmp(argv[0], "empty") == 0)
494                                 *dbdata = &empty_builtin;
495                         else
496                                 *dbdata = &dns64_builtin;
497                         if (server != NULL)
498                                 isc_mem_free(ns_g_mctx, server);
499                         if (contact != NULL)
500                                 isc_mem_free(ns_g_mctx, contact);
501                         if (empty != NULL)
502                                 isc_mem_put(ns_g_mctx, empty, sizeof (*empty));
503                 } else {
504                         if (strcmp(argv[0], "empty") == 0)
505                                 memmove(empty, &empty_builtin,
506                                         sizeof (empty_builtin));
507                         else
508                                 memmove(empty, &dns64_builtin,
509                                         sizeof (empty_builtin));
510                         empty->server = server;
511                         empty->contact = contact;
512                         *dbdata = empty;
513                 }
514         } else
515                 return (ISC_R_NOTIMPLEMENTED);
516         return (ISC_R_SUCCESS);
517 }
518
519 static void
520 builtin_destroy(const char *zone, void *driverdata, void **dbdata) {
521         builtin_t *b = (builtin_t *) *dbdata;
522
523         UNUSED(zone);
524         UNUSED(driverdata);
525
526         /*
527          * Don't free the static versions.
528          */
529         if (*dbdata == &version_builtin || *dbdata == &hostname_builtin ||
530             *dbdata == &authors_builtin || *dbdata == &id_builtin ||
531             *dbdata == &empty_builtin || *dbdata == &dns64_builtin)
532                 return;
533
534         isc_mem_free(ns_g_mctx, b->server);
535         isc_mem_free(ns_g_mctx, b->contact);
536         isc_mem_put(ns_g_mctx, b, sizeof (*b));
537 }
538
539 static dns_sdbmethods_t builtin_methods = {
540         builtin_lookup,
541         builtin_authority,
542         NULL,           /* allnodes */
543         builtin_create,
544         builtin_destroy,
545         NULL
546 };
547
548 static dns_sdbmethods_t dns64_methods = {
549         NULL,
550         builtin_authority,
551         NULL,           /* allnodes */
552         builtin_create,
553         builtin_destroy,
554         dns64_lookup,
555 };
556
557 isc_result_t
558 ns_builtin_init(void) {
559         RUNTIME_CHECK(dns_sdb_register("_builtin", &builtin_methods, NULL,
560                                        DNS_SDBFLAG_RELATIVEOWNER |
561                                        DNS_SDBFLAG_RELATIVERDATA,
562                                        ns_g_mctx, &builtin_impl)
563                       == ISC_R_SUCCESS);
564         RUNTIME_CHECK(dns_sdb_register("_dns64", &dns64_methods, NULL,
565                                        DNS_SDBFLAG_RELATIVEOWNER |
566                                        DNS_SDBFLAG_RELATIVERDATA |
567                                        DNS_SDBFLAG_DNS64,
568                                        ns_g_mctx, &dns64_impl)
569                       == ISC_R_SUCCESS);
570         return (ISC_R_SUCCESS);
571 }
572
573 void
574 ns_builtin_deinit(void) {
575         dns_sdb_unregister(&builtin_impl);
576         dns_sdb_unregister(&dns64_impl);
577 }