Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / contrib / dlz / example / dlz_example.c
blobc90636a58a6741d5e3489b2b34ed641f0f5e5f7c
1 /* $NetBSD: dlz_example.c,v 1.7 2014/12/10 04:37:55 christos Exp $ */
3 /*
4 * Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
20 * This provides a very simple example of an external loadable DLZ
21 * driver, with update support.
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdarg.h>
28 #include <stdint.h>
30 #include "../modules/include/dlz_minimal.h"
32 #ifdef WIN32
33 #define STRTOK_R(a, b, c) strtok_s(a, b, c)
34 #elif defined(_REENTRANT)
35 #define STRTOK_R(a, b, c) strtok_r(a, b, c)
36 #else
37 #define STRTOK_R(a, b, c) strtok(a, b)
38 #endif
40 #define CHECK(x) \
41 do { \
42 result = (x); \
43 if (result != ISC_R_SUCCESS) \
44 goto failure; \
45 } while (/*CONSTCOND*/0)
47 /* For this simple example, use fixed sized strings */
48 struct record {
49 char name[100];
50 char type[10];
51 char data[200];
52 dns_ttl_t ttl;
55 #define MAX_RECORDS 100
57 struct dlz_example_data {
58 char *zone_name;
60 /* An example driver doesn't need good memory management :-) */
61 struct record current[MAX_RECORDS];
62 struct record adds[MAX_RECORDS];
63 struct record deletes[MAX_RECORDS];
65 isc_boolean_t transaction_started;
67 /* Helper functions from the dlz_dlopen driver */
68 log_t *log;
69 dns_sdlz_putrr_t *putrr;
70 dns_sdlz_putnamedrr_t *putnamedrr;
71 dns_dlz_writeablezone_t *writeable_zone;
74 static isc_boolean_t
75 single_valued(const char *type) {
76 const char *single[] = { "soa", "cname", NULL };
77 int i;
79 for (i = 0; single[i]; i++) {
80 if (strcasecmp(single[i], type) == 0) {
81 return (ISC_TRUE);
84 return (ISC_FALSE);
88 * Add a record to a list
90 static isc_result_t
91 add_name(struct dlz_example_data *state, struct record *list,
92 const char *name, const char *type, dns_ttl_t ttl, const char *data)
94 int i;
95 isc_boolean_t single = single_valued(type);
96 int first_empty = -1;
98 for (i = 0; i < MAX_RECORDS; i++) {
99 if (first_empty == -1 && strlen(list[i].name) == 0U) {
100 first_empty = i;
102 if (strcasecmp(list[i].name, name) != 0)
103 continue;
104 if (strcasecmp(list[i].type, type) != 0)
105 continue;
106 if (!single && strcasecmp(list[i].data, data) != 0)
107 continue;
108 break;
110 if (i == MAX_RECORDS && first_empty != -1) {
111 i = first_empty;
113 if (i == MAX_RECORDS) {
114 if (state->log != NULL)
115 state->log(ISC_LOG_ERROR,
116 "dlz_example: out of record space");
117 return (ISC_R_FAILURE);
120 if (strlen(name) >= sizeof(list[i].name) ||
121 strlen(type) >= sizeof(list[i].type) ||
122 strlen(data) >= sizeof(list[i].data))
123 return (ISC_R_NOSPACE);
125 strncpy(list[i].name, name, sizeof(list[i].name));
126 list[i].name[sizeof(list[i].name) - 1] = '\0';
128 strncpy(list[i].type, type, sizeof(list[i].type));
129 list[i].type[sizeof(list[i].type) - 1] = '\0';
131 strncpy(list[i].data, data, sizeof(list[i].data));
132 list[i].data[sizeof(list[i].data) - 1] = '\0';
134 list[i].ttl = ttl;
136 return (ISC_R_SUCCESS);
140 * Delete a record from a list
142 static isc_result_t
143 del_name(struct dlz_example_data *state, struct record *list,
144 const char *name, const char *type, dns_ttl_t ttl,
145 const char *data)
147 int i;
149 UNUSED(state);
151 for (i = 0; i < MAX_RECORDS; i++) {
152 if (strcasecmp(name, list[i].name) == 0 &&
153 strcasecmp(type, list[i].type) == 0 &&
154 strcasecmp(data, list[i].data) == 0 &&
155 ttl == list[i].ttl) {
156 break;
159 if (i == MAX_RECORDS) {
160 return (ISC_R_NOTFOUND);
162 memset(&list[i], 0, sizeof(struct record));
163 return (ISC_R_SUCCESS);
166 static isc_result_t
167 fmt_address(isc_sockaddr_t *addr, char *buffer, size_t size) {
168 char addr_buf[100];
169 const char *ret;
170 uint16_t port = 0;
172 switch (addr->type.sa.sa_family) {
173 case AF_INET:
174 port = ntohs(addr->type.sin.sin_port);
175 ret = inet_ntop(AF_INET, &addr->type.sin.sin_addr, addr_buf,
176 sizeof(addr_buf));
177 break;
178 case AF_INET6:
179 port = ntohs(addr->type.sin6.sin6_port);
180 ret = inet_ntop(AF_INET6, &addr->type.sin6.sin6_addr, addr_buf,
181 sizeof(addr_buf));
182 break;
183 default:
184 return (ISC_R_FAILURE);
187 if (ret == NULL)
188 return (ISC_R_FAILURE);
190 snprintf(buffer, size, "%s#%u", addr_buf, port);
191 return (ISC_R_SUCCESS);
195 * Return the version of the API
198 dlz_version(unsigned int *flags) {
199 UNUSED(flags);
200 return (DLZ_DLOPEN_VERSION);
204 * Remember a helper function from the bind9 dlz_dlopen driver
206 static void
207 b9_add_helper(struct dlz_example_data *state,
208 const char *helper_name, void *ptr)
210 if (strcmp(helper_name, "log") == 0)
211 state->log = (log_t *)ptr;
212 if (strcmp(helper_name, "putrr") == 0)
213 state->putrr = (dns_sdlz_putrr_t *)ptr;
214 if (strcmp(helper_name, "putnamedrr") == 0)
215 state->putnamedrr = (dns_sdlz_putnamedrr_t *)ptr;
216 if (strcmp(helper_name, "writeable_zone") == 0)
217 state->writeable_zone = (dns_dlz_writeablezone_t *)ptr;
221 * Called to initialize the driver
223 isc_result_t
224 dlz_create(const char *dlzname, unsigned int argc, char *argv[],
225 void **dbdata, ...)
227 struct dlz_example_data *state;
228 const char *helper_name;
229 va_list ap;
230 char soa_data[200];
231 const char *extra;
232 isc_result_t result;
233 int n;
235 UNUSED(dlzname);
237 state = calloc(1, sizeof(struct dlz_example_data));
238 if (state == NULL)
239 return (ISC_R_NOMEMORY);
241 /* Fill in the helper functions */
242 va_start(ap, dbdata);
243 while ((helper_name = va_arg(ap, const char *)) != NULL) {
244 b9_add_helper(state, helper_name, va_arg(ap, void *));
246 va_end(ap);
248 if (argc < 2 || argv[1][0] == '\0') {
249 if (state->log != NULL)
250 state->log(ISC_LOG_ERROR,
251 "dlz_example: please specify a zone name");
252 dlz_destroy(state);
253 return (ISC_R_FAILURE);
256 /* Ensure zone name is absolute */
257 state->zone_name = malloc(strlen(argv[1]) + 2);
258 if (state->zone_name == NULL) {
259 free(state);
260 return (ISC_R_NOMEMORY);
262 if (argv[1][strlen(argv[1]) - 1] == '.')
263 strcpy(state->zone_name, argv[1]);
264 else
265 sprintf(state->zone_name, "%s.", argv[1]);
267 if (strcmp(state->zone_name, ".") == 0)
268 extra = ".root";
269 else
270 extra = ".";
272 n = sprintf(soa_data, "%s hostmaster%s%s 123 900 600 86400 3600",
273 state->zone_name, extra, state->zone_name);
275 if (n < 0)
276 CHECK(ISC_R_FAILURE);
277 if ((unsigned)n >= sizeof(soa_data))
278 CHECK(ISC_R_NOSPACE);
280 add_name(state, &state->current[0], state->zone_name,
281 "soa", 3600, soa_data);
282 add_name(state, &state->current[0], state->zone_name,
283 "ns", 3600, state->zone_name);
284 add_name(state, &state->current[0], state->zone_name,
285 "a", 1800, "10.53.0.1");
287 if (state->log != NULL)
288 state->log(ISC_LOG_INFO, "dlz_example: started for zone %s",
289 state->zone_name);
291 *dbdata = state;
292 return (ISC_R_SUCCESS);
294 failure:
295 free(state);
296 return (result);
301 * Shut down the backend
303 void
304 dlz_destroy(void *dbdata) {
305 struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
307 if (state->log != NULL)
308 state->log(ISC_LOG_INFO,
309 "dlz_example: shutting down zone %s",
310 state->zone_name);
311 free(state->zone_name);
312 free(state);
316 * See if we handle a given zone
318 isc_result_t
319 dlz_findzonedb(void *dbdata, const char *name,
320 dns_clientinfomethods_t *methods,
321 dns_clientinfo_t *clientinfo)
323 struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
324 isc_sockaddr_t *src;
325 char addrbuf[100];
326 char absolute[1024];
328 strcpy(addrbuf, "unknown");
329 if (methods != NULL &&
330 methods->sourceip != NULL &&
331 methods->version - methods->age <= DNS_CLIENTINFOMETHODS_VERSION &&
332 DNS_CLIENTINFOMETHODS_VERSION <= methods->version)
334 methods->sourceip(clientinfo, &src);
335 fmt_address(src, addrbuf, sizeof(addrbuf));
337 state->log(ISC_LOG_INFO,
338 "dlz_example: findzonedb connection from: %s\n", addrbuf);
340 state->log(ISC_LOG_INFO,
341 "dlz_example: dlz_findzonedb called with name '%s' "
342 "in zone DB '%s'", name, state->zone_name);
345 * Returning ISC_R_NOTFOUND will cause the query logic to
346 * check the database for parent names, looking for zone cuts.
348 * Returning ISC_R_NOMORE prevents the query logic from doing
349 * this; it will move onto the next database after a single query.
351 if (strcasecmp(name, "test.example.com") == 0)
352 return (ISC_R_NOMORE);
355 * For example.net, only return ISC_R_NOMORE when queried
356 * from 10.53.0.1.
358 if (strcasecmp(name, "test.example.net") == 0 &&
359 strncmp(addrbuf, "10.53.0.1", 9) == 0)
360 return (ISC_R_NOMORE);
362 if (strcasecmp(state->zone_name, name) == 0)
363 return (ISC_R_SUCCESS);
365 snprintf(absolute, sizeof(absolute), "%s.", name);
366 if (strcasecmp(state->zone_name, absolute) == 0)
367 return (ISC_R_SUCCESS);
369 return (ISC_R_NOTFOUND);
373 * Look up one record in the sample database.
375 * If the queryname is "source-addr", send back a TXT record containing
376 * the address of the client; this demonstrates the use of 'methods'
377 * and 'clientinfo'.
379 * If the queryname is "too-long", send back a TXT record that's too long
380 * to process; this should result in a SERVFAIL when queried.
382 isc_result_t
383 dlz_lookup(const char *zone, const char *name, void *dbdata,
384 dns_sdlzlookup_t *lookup, dns_clientinfomethods_t *methods,
385 dns_clientinfo_t *clientinfo)
387 isc_result_t result;
388 struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
389 isc_boolean_t found = ISC_FALSE;
390 isc_sockaddr_t *src;
391 char full_name[256];
392 char buf[512];
393 int i;
395 UNUSED(zone);
397 if (state->putrr == NULL)
398 return (ISC_R_NOTIMPLEMENTED);
400 if (strcmp(name, "@") == 0) {
401 strncpy(full_name, state->zone_name, 255);
402 full_name[255] = '\0';
403 } else
404 snprintf(full_name, 255, "%s.%s", name, state->zone_name);
406 if (strcmp(name, "source-addr") == 0) {
407 strcpy(buf, "unknown");
408 if (methods != NULL &&
409 methods->sourceip != NULL &&
410 (methods->version - methods->age <=
411 DNS_CLIENTINFOMETHODS_VERSION) &&
412 DNS_CLIENTINFOMETHODS_VERSION <= methods->version)
414 methods->sourceip(clientinfo, &src);
415 fmt_address(src, buf, sizeof(buf));
418 state->log(ISC_LOG_INFO,
419 "dlz_example: lookup connection from: %s\n", buf);
421 found = ISC_TRUE;
422 result = state->putrr(lookup, "TXT", 0, buf);
423 if (result != ISC_R_SUCCESS)
424 return (result);
427 if (strcmp(name, "too-long") == 0) {
428 for (i = 0; i < 511; i++)
429 buf[i] = 'x';
430 buf[i] = '\0';
431 found = ISC_TRUE;
432 result = state->putrr(lookup, "TXT", 0, buf);
433 if (result != ISC_R_SUCCESS)
434 return (result);
437 for (i = 0; i < MAX_RECORDS; i++) {
438 if (strcasecmp(state->current[i].name, full_name) == 0) {
439 found = ISC_TRUE;
440 result = state->putrr(lookup, state->current[i].type,
441 state->current[i].ttl,
442 state->current[i].data);
443 if (result != ISC_R_SUCCESS)
444 return (result);
448 if (!found)
449 return (ISC_R_NOTFOUND);
451 return (ISC_R_SUCCESS);
456 * See if a zone transfer is allowed
458 isc_result_t
459 dlz_allowzonexfr(void *dbdata, const char *name, const char *client) {
460 UNUSED(client);
462 /* Just say yes for all our zones */
463 return (dlz_findzonedb(dbdata, name, NULL, NULL));
467 * Perform a zone transfer
469 isc_result_t
470 dlz_allnodes(const char *zone, void *dbdata, dns_sdlzallnodes_t *allnodes) {
471 struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
472 int i;
474 UNUSED(zone);
476 if (state->putnamedrr == NULL)
477 return (ISC_R_NOTIMPLEMENTED);
479 for (i = 0; i < MAX_RECORDS; i++) {
480 isc_result_t result;
481 if (strlen(state->current[i].name) == 0U) {
482 continue;
484 result = state->putnamedrr(allnodes, state->current[i].name,
485 state->current[i].type,
486 state->current[i].ttl,
487 state->current[i].data);
488 if (result != ISC_R_SUCCESS)
489 return (result);
492 return (ISC_R_SUCCESS);
497 * Start a transaction
499 isc_result_t
500 dlz_newversion(const char *zone, void *dbdata, void **versionp) {
501 struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
503 if (state->transaction_started) {
504 if (state->log != NULL)
505 state->log(ISC_LOG_INFO,
506 "dlz_example: transaction already "
507 "started for zone %s", zone);
508 return (ISC_R_FAILURE);
511 state->transaction_started = ISC_TRUE;
512 *versionp = (void *) &state->transaction_started;
514 return (ISC_R_SUCCESS);
518 * End a transaction
520 void
521 dlz_closeversion(const char *zone, isc_boolean_t commit,
522 void *dbdata, void **versionp)
524 struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
526 if (!state->transaction_started) {
527 if (state->log != NULL)
528 state->log(ISC_LOG_INFO, "dlz_example: transaction not "
529 "started for zone %s", zone);
530 *versionp = NULL;
531 return;
534 state->transaction_started = ISC_FALSE;
536 *versionp = NULL;
538 if (commit) {
539 int i;
540 if (state->log != NULL)
541 state->log(ISC_LOG_INFO, "dlz_example: committing "
542 "transaction on zone %s", zone);
543 for (i = 0; i < MAX_RECORDS; i++) {
544 if (strlen(state->deletes[i].name) > 0U) {
545 (void)del_name(state, &state->current[0],
546 state->deletes[i].name,
547 state->deletes[i].type,
548 state->deletes[i].ttl,
549 state->deletes[i].data);
552 for (i = 0; i < MAX_RECORDS; i++) {
553 if (strlen(state->adds[i].name) > 0U) {
554 (void)add_name(state, &state->current[0],
555 state->adds[i].name,
556 state->adds[i].type,
557 state->adds[i].ttl,
558 state->adds[i].data);
561 } else {
562 if (state->log != NULL)
563 state->log(ISC_LOG_INFO, "dlz_example: cancelling "
564 "transaction on zone %s", zone);
566 memset(state->adds, 0, sizeof(state->adds));
567 memset(state->deletes, 0, sizeof(state->deletes));
572 * Configure a writeable zone
574 isc_result_t
575 dlz_configure(dns_view_t *view, dns_dlzdb_t *dlzdb, void *dbdata) {
576 struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
577 isc_result_t result;
579 if (state->log != NULL)
580 state->log(ISC_LOG_INFO, "dlz_example: starting configure");
582 if (state->writeable_zone == NULL) {
583 if (state->log != NULL)
584 state->log(ISC_LOG_INFO, "dlz_example: no "
585 "writeable_zone method available");
586 return (ISC_R_FAILURE);
589 result = state->writeable_zone(view, dlzdb, state->zone_name);
590 if (result != ISC_R_SUCCESS) {
591 if (state->log != NULL)
592 state->log(ISC_LOG_ERROR, "dlz_example: failed to "
593 "configure zone %s", state->zone_name);
594 return (result);
597 if (state->log != NULL)
598 state->log(ISC_LOG_INFO, "dlz_example: configured writeable "
599 "zone %s", state->zone_name);
600 return (ISC_R_SUCCESS);
604 * Authorize a zone update
606 isc_boolean_t
607 dlz_ssumatch(const char *signer, const char *name, const char *tcpaddr,
608 const char *type, const char *key, uint32_t keydatalen,
609 unsigned char *keydata, void *dbdata)
611 struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
613 UNUSED(tcpaddr);
614 UNUSED(type);
615 UNUSED(key);
616 UNUSED(keydatalen);
617 UNUSED(keydata);
619 if (strncmp(name, "deny.", 5) == 0) {
620 if (state->log != NULL)
621 state->log(ISC_LOG_INFO, "dlz_example: denying update "
622 "of name=%s by %s", name, signer);
623 return (ISC_FALSE);
625 if (state->log != NULL)
626 state->log(ISC_LOG_INFO, "dlz_example: allowing update of "
627 "name=%s by %s", name, signer);
628 return (ISC_TRUE);
632 static isc_result_t
633 modrdataset(struct dlz_example_data *state, const char *name,
634 const char *rdatastr, struct record *list)
636 char *full_name, *dclass, *type, *data, *ttlstr, *buf;
637 char absolute[1024];
638 isc_result_t result;
639 #if defined(WIN32) || defined(_REENTRANT)
640 char *saveptr = NULL;
641 #endif
643 buf = strdup(rdatastr);
644 if (buf == NULL)
645 return (ISC_R_FAILURE);
648 * The format is:
649 * FULLNAME\tTTL\tDCLASS\tTYPE\tDATA
651 * The DATA field is space separated, and is in the data format
652 * for the type used by dig
655 full_name = STRTOK_R(buf, "\t", &saveptr);
656 if (full_name == NULL)
657 goto error;
659 ttlstr = STRTOK_R(NULL, "\t", &saveptr);
660 if (ttlstr == NULL)
661 goto error;
663 dclass = STRTOK_R(NULL, "\t", &saveptr);
664 if (dclass == NULL)
665 goto error;
667 type = STRTOK_R(NULL, "\t", &saveptr);
668 if (type == NULL)
669 goto error;
671 data = STRTOK_R(NULL, "\t", &saveptr);
672 if (data == NULL)
673 goto error;
675 if (name[strlen(name) - 1] != '.') {
676 snprintf(absolute, sizeof(absolute), "%s.", name);
677 name = absolute;
680 result = add_name(state, list, name, type,
681 strtoul(ttlstr, NULL, 10), data);
682 free(buf);
683 return (result);
685 error:
686 free(buf);
687 return (ISC_R_FAILURE);
691 isc_result_t
692 dlz_addrdataset(const char *name, const char *rdatastr,
693 void *dbdata, void *version)
695 struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
697 if (version != (void *) &state->transaction_started)
698 return (ISC_R_FAILURE);
700 if (state->log != NULL)
701 state->log(ISC_LOG_INFO, "dlz_example: adding rdataset %s '%s'",
702 name, rdatastr);
704 return (modrdataset(state, name, rdatastr, &state->adds[0]));
707 isc_result_t
708 dlz_subrdataset(const char *name, const char *rdatastr,
709 void *dbdata, void *version)
711 struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
713 if (version != (void *) &state->transaction_started)
714 return (ISC_R_FAILURE);
716 if (state->log != NULL)
717 state->log(ISC_LOG_INFO, "dlz_example: subtracting rdataset "
718 "%s '%s'", name, rdatastr);
720 return (modrdataset(state, name, rdatastr, &state->deletes[0]));
723 isc_result_t
724 dlz_delrdataset(const char *name, const char *type,
725 void *dbdata, void *version)
727 struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
729 if (version != (void *) &state->transaction_started)
730 return (ISC_R_FAILURE);
732 if (state->log != NULL)
733 state->log(ISC_LOG_INFO, "dlz_example: deleting rdataset %s "
734 "of type %s", name, type);
736 return (ISC_R_SUCCESS);