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