xref: /minix3/external/bsd/bind/dist/contrib/dlz/example/dlz_example.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
1 /*	$NetBSD: dlz_example.c,v 1.7 2014/12/10 04:37:55 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
5  *
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.
9  *
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.
17  */
18 
19 /*
20  * This provides a very simple example of an external loadable DLZ
21  * driver, with update support.
22  */
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdarg.h>
28 #include <stdint.h>
29 
30 #include "../modules/include/dlz_minimal.h"
31 
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
39 
40 #define CHECK(x) \
41 	do { \
42 		result = (x); \
43 		if (result != ISC_R_SUCCESS) \
44 			goto failure; \
45 	} while (/*CONSTCOND*/0)
46 
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;
53 };
54 
55 #define MAX_RECORDS 100
56 
57 struct dlz_example_data {
58 	char *zone_name;
59 
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];
64 
65 	isc_boolean_t transaction_started;
66 
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;
72 };
73 
74 static isc_boolean_t
single_valued(const char * type)75 single_valued(const char *type) {
76 	const char *single[] = { "soa", "cname", NULL };
77 	int i;
78 
79 	for (i = 0; single[i]; i++) {
80 		if (strcasecmp(single[i], type) == 0) {
81 			return (ISC_TRUE);
82 		}
83 	}
84 	return (ISC_FALSE);
85 }
86 
87 /*
88  * Add a record to a list
89  */
90 static isc_result_t
add_name(struct dlz_example_data * state,struct record * list,const char * name,const char * type,dns_ttl_t ttl,const char * data)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)
93 {
94 	int i;
95 	isc_boolean_t single = single_valued(type);
96 	int first_empty = -1;
97 
98 	for (i = 0; i < MAX_RECORDS; i++) {
99 		if (first_empty == -1 && strlen(list[i].name) == 0U) {
100 			first_empty = i;
101 		}
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;
109 	}
110 	if (i == MAX_RECORDS && first_empty != -1) {
111 		i = first_empty;
112 	}
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);
118 	}
119 
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);
124 
125 	strncpy(list[i].name, name, sizeof(list[i].name));
126 	list[i].name[sizeof(list[i].name) - 1] = '\0';
127 
128 	strncpy(list[i].type, type, sizeof(list[i].type));
129 	list[i].type[sizeof(list[i].type) - 1] = '\0';
130 
131 	strncpy(list[i].data, data, sizeof(list[i].data));
132 	list[i].data[sizeof(list[i].data) - 1] = '\0';
133 
134 	list[i].ttl = ttl;
135 
136 	return (ISC_R_SUCCESS);
137 }
138 
139 /*
140  * Delete a record from a list
141  */
142 static isc_result_t
del_name(struct dlz_example_data * state,struct record * list,const char * name,const char * type,dns_ttl_t ttl,const char * data)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)
146 {
147 	int i;
148 
149 	UNUSED(state);
150 
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;
157 		}
158 	}
159 	if (i == MAX_RECORDS) {
160 		return (ISC_R_NOTFOUND);
161 	}
162 	memset(&list[i], 0, sizeof(struct record));
163 	return (ISC_R_SUCCESS);
164 }
165 
166 static isc_result_t
fmt_address(isc_sockaddr_t * addr,char * buffer,size_t size)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;
171 
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);
185 	}
186 
187 	if (ret == NULL)
188 		return (ISC_R_FAILURE);
189 
190 	snprintf(buffer, size, "%s#%u", addr_buf, port);
191 	return (ISC_R_SUCCESS);
192 }
193 
194 /*
195  * Return the version of the API
196  */
197 int
dlz_version(unsigned int * flags)198 dlz_version(unsigned int *flags) {
199 	UNUSED(flags);
200 	return (DLZ_DLOPEN_VERSION);
201 }
202 
203 /*
204  * Remember a helper function from the bind9 dlz_dlopen driver
205  */
206 static void
b9_add_helper(struct dlz_example_data * state,const char * helper_name,void * ptr)207 b9_add_helper(struct dlz_example_data *state,
208 	      const char *helper_name, void *ptr)
209 {
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;
218 }
219 
220 /*
221  * Called to initialize the driver
222  */
223 isc_result_t
dlz_create(const char * dlzname,unsigned int argc,char * argv[],void ** dbdata,...)224 dlz_create(const char *dlzname, unsigned int argc, char *argv[],
225 	   void **dbdata, ...)
226 {
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;
234 
235 	UNUSED(dlzname);
236 
237 	state = calloc(1, sizeof(struct dlz_example_data));
238 	if (state == NULL)
239 		return (ISC_R_NOMEMORY);
240 
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 *));
245 	}
246 	va_end(ap);
247 
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);
254 	}
255 
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);
261 	}
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]);
266 
267 	if (strcmp(state->zone_name, ".") == 0)
268 		extra = ".root";
269 	else
270 		extra = ".";
271 
272 	n = sprintf(soa_data, "%s hostmaster%s%s 123 900 600 86400 3600",
273 		    state->zone_name, extra, state->zone_name);
274 
275 	if (n < 0)
276 		CHECK(ISC_R_FAILURE);
277 	if ((unsigned)n >= sizeof(soa_data))
278 		CHECK(ISC_R_NOSPACE);
279 
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");
286 
287 	if (state->log != NULL)
288 		state->log(ISC_LOG_INFO, "dlz_example: started for zone %s",
289 			   state->zone_name);
290 
291 	*dbdata = state;
292 	return (ISC_R_SUCCESS);
293 
294  failure:
295 	free(state);
296 	return (result);
297 
298 }
299 
300 /*
301  * Shut down the backend
302  */
303 void
dlz_destroy(void * dbdata)304 dlz_destroy(void *dbdata) {
305 	struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
306 
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);
313 }
314 
315 /*
316  * See if we handle a given zone
317  */
318 isc_result_t
dlz_findzonedb(void * dbdata,const char * name,dns_clientinfomethods_t * methods,dns_clientinfo_t * clientinfo)319 dlz_findzonedb(void *dbdata, const char *name,
320 	   dns_clientinfomethods_t *methods,
321 	   dns_clientinfo_t *clientinfo)
322 {
323 	struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
324 	isc_sockaddr_t *src;
325 	char addrbuf[100];
326 	char absolute[1024];
327 
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)
333 	{
334 		methods->sourceip(clientinfo, &src);
335 		fmt_address(src, addrbuf, sizeof(addrbuf));
336 	}
337 	state->log(ISC_LOG_INFO,
338 		   "dlz_example: findzonedb connection from: %s\n", addrbuf);
339 
340 	state->log(ISC_LOG_INFO,
341 		   "dlz_example: dlz_findzonedb called with name '%s' "
342 		   "in zone DB '%s'", name, state->zone_name);
343 
344 	/*
345 	 * Returning ISC_R_NOTFOUND will cause the query logic to
346 	 * check the database for parent names, looking for zone cuts.
347 	 *
348 	 * Returning ISC_R_NOMORE prevents the query logic from doing
349 	 * this; it will move onto the next database after a single query.
350 	 */
351 	if (strcasecmp(name, "test.example.com") == 0)
352 		return (ISC_R_NOMORE);
353 
354 	/*
355 	 * For example.net, only return ISC_R_NOMORE when queried
356 	 * from 10.53.0.1.
357 	 */
358 	if (strcasecmp(name, "test.example.net") == 0 &&
359 	    strncmp(addrbuf, "10.53.0.1", 9) == 0)
360 		return (ISC_R_NOMORE);
361 
362 	if (strcasecmp(state->zone_name, name) == 0)
363 		return (ISC_R_SUCCESS);
364 
365 	snprintf(absolute, sizeof(absolute), "%s.", name);
366 	if (strcasecmp(state->zone_name, absolute) == 0)
367 		return (ISC_R_SUCCESS);
368 
369 	return (ISC_R_NOTFOUND);
370 }
371 
372 /*
373  * Look up one record in the sample database.
374  *
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'.
378  *
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.
381  */
382 isc_result_t
dlz_lookup(const char * zone,const char * name,void * dbdata,dns_sdlzlookup_t * lookup,dns_clientinfomethods_t * methods,dns_clientinfo_t * clientinfo)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)
386 {
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;
394 
395 	UNUSED(zone);
396 
397 	if (state->putrr == NULL)
398 		return (ISC_R_NOTIMPLEMENTED);
399 
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);
405 
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)
413 		{
414 			methods->sourceip(clientinfo, &src);
415 			fmt_address(src, buf, sizeof(buf));
416 		}
417 
418 		state->log(ISC_LOG_INFO,
419 			   "dlz_example: lookup connection from: %s\n", buf);
420 
421 		found = ISC_TRUE;
422 		result = state->putrr(lookup, "TXT", 0, buf);
423 		if (result != ISC_R_SUCCESS)
424 			return (result);
425 	}
426 
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);
435 	}
436 
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);
445 		}
446 	}
447 
448 	if (!found)
449 		return (ISC_R_NOTFOUND);
450 
451 	return (ISC_R_SUCCESS);
452 }
453 
454 
455 /*
456  * See if a zone transfer is allowed
457  */
458 isc_result_t
dlz_allowzonexfr(void * dbdata,const char * name,const char * client)459 dlz_allowzonexfr(void *dbdata, const char *name, const char *client) {
460 	UNUSED(client);
461 
462 	/* Just say yes for all our zones */
463 	return (dlz_findzonedb(dbdata, name, NULL, NULL));
464 }
465 
466 /*
467  * Perform a zone transfer
468  */
469 isc_result_t
dlz_allnodes(const char * zone,void * dbdata,dns_sdlzallnodes_t * allnodes)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;
473 
474 	UNUSED(zone);
475 
476 	if (state->putnamedrr == NULL)
477 		return (ISC_R_NOTIMPLEMENTED);
478 
479 	for (i = 0; i < MAX_RECORDS; i++) {
480 		isc_result_t result;
481 		if (strlen(state->current[i].name) == 0U) {
482 			continue;
483 		}
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);
490 	}
491 
492 	return (ISC_R_SUCCESS);
493 }
494 
495 
496 /*
497  * Start a transaction
498  */
499 isc_result_t
dlz_newversion(const char * zone,void * dbdata,void ** versionp)500 dlz_newversion(const char *zone, void *dbdata, void **versionp) {
501 	struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
502 
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);
509 	}
510 
511 	state->transaction_started = ISC_TRUE;
512 	*versionp = (void *) &state->transaction_started;
513 
514 	return (ISC_R_SUCCESS);
515 }
516 
517 /*
518  * End a transaction
519  */
520 void
dlz_closeversion(const char * zone,isc_boolean_t commit,void * dbdata,void ** versionp)521 dlz_closeversion(const char *zone, isc_boolean_t commit,
522 		 void *dbdata, void **versionp)
523 {
524 	struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
525 
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;
532 	}
533 
534 	state->transaction_started = ISC_FALSE;
535 
536 	*versionp = NULL;
537 
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);
550 			}
551 		}
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);
559 			}
560 		}
561 	} else {
562 		if (state->log != NULL)
563 			state->log(ISC_LOG_INFO, "dlz_example: cancelling "
564 				   "transaction on zone %s", zone);
565 	}
566 	memset(state->adds, 0, sizeof(state->adds));
567 	memset(state->deletes, 0, sizeof(state->deletes));
568 }
569 
570 
571 /*
572  * Configure a writeable zone
573  */
574 isc_result_t
dlz_configure(dns_view_t * view,dns_dlzdb_t * dlzdb,void * dbdata)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;
578 
579 	if (state->log != NULL)
580 		state->log(ISC_LOG_INFO, "dlz_example: starting configure");
581 
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);
587 	}
588 
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);
595 	}
596 
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);
601 }
602 
603 /*
604  * Authorize a zone update
605  */
606 isc_boolean_t
dlz_ssumatch(const char * signer,const char * name,const char * tcpaddr,const char * type,const char * key,uint32_t keydatalen,unsigned char * keydata,void * dbdata)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)
610 {
611 	struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
612 
613 	UNUSED(tcpaddr);
614 	UNUSED(type);
615 	UNUSED(key);
616 	UNUSED(keydatalen);
617 	UNUSED(keydata);
618 
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);
624 	}
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);
629 }
630 
631 
632 static isc_result_t
modrdataset(struct dlz_example_data * state,const char * name,const char * rdatastr,struct record * list)633 modrdataset(struct dlz_example_data *state, const char *name,
634 	    const char *rdatastr, struct record *list)
635 {
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
642 
643 	buf = strdup(rdatastr);
644 	if (buf == NULL)
645 		return (ISC_R_FAILURE);
646 
647 	/*
648 	 * The format is:
649 	 * FULLNAME\tTTL\tDCLASS\tTYPE\tDATA
650 	 *
651 	 * The DATA field is space separated, and is in the data format
652 	 * for the type used by dig
653 	 */
654 
655 	full_name = STRTOK_R(buf, "\t", &saveptr);
656 	if (full_name == NULL)
657 		goto error;
658 
659 	ttlstr = STRTOK_R(NULL, "\t", &saveptr);
660 	if (ttlstr == NULL)
661 		goto error;
662 
663 	dclass = STRTOK_R(NULL, "\t", &saveptr);
664 	if (dclass == NULL)
665 		goto error;
666 
667 	type = STRTOK_R(NULL, "\t", &saveptr);
668 	if (type == NULL)
669 		goto error;
670 
671 	data = STRTOK_R(NULL, "\t", &saveptr);
672 	if (data == NULL)
673 		goto error;
674 
675 	if (name[strlen(name) - 1] != '.') {
676 		snprintf(absolute, sizeof(absolute), "%s.", name);
677 		name = absolute;
678 	}
679 
680 	result = add_name(state, list, name, type,
681 			  strtoul(ttlstr, NULL, 10), data);
682 	free(buf);
683 	return (result);
684 
685  error:
686 	free(buf);
687 	return (ISC_R_FAILURE);
688 }
689 
690 
691 isc_result_t
dlz_addrdataset(const char * name,const char * rdatastr,void * dbdata,void * version)692 dlz_addrdataset(const char *name, const char *rdatastr,
693 		void *dbdata, void *version)
694 {
695 	struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
696 
697 	if (version != (void *) &state->transaction_started)
698 		return (ISC_R_FAILURE);
699 
700 	if (state->log != NULL)
701 		state->log(ISC_LOG_INFO, "dlz_example: adding rdataset %s '%s'",
702 			   name, rdatastr);
703 
704 	return (modrdataset(state, name, rdatastr, &state->adds[0]));
705 }
706 
707 isc_result_t
dlz_subrdataset(const char * name,const char * rdatastr,void * dbdata,void * version)708 dlz_subrdataset(const char *name, const char *rdatastr,
709 		void *dbdata, void *version)
710 {
711 	struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
712 
713 	if (version != (void *) &state->transaction_started)
714 		return (ISC_R_FAILURE);
715 
716 	if (state->log != NULL)
717 		state->log(ISC_LOG_INFO, "dlz_example: subtracting rdataset "
718 			   "%s '%s'", name, rdatastr);
719 
720 	return (modrdataset(state, name, rdatastr, &state->deletes[0]));
721 }
722 
723 isc_result_t
dlz_delrdataset(const char * name,const char * type,void * dbdata,void * version)724 dlz_delrdataset(const char *name, const char *type,
725 		void *dbdata, void *version)
726 {
727 	struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
728 
729 	if (version != (void *) &state->transaction_started)
730 		return (ISC_R_FAILURE);
731 
732 	if (state->log != NULL)
733 		state->log(ISC_LOG_INFO, "dlz_example: deleting rdataset %s "
734 			   "of type %s", name, type);
735 
736 	return (ISC_R_SUCCESS);
737 }
738