4 * Copyright (C) 2009 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.
19 /* Id: sample-update.c,v 1.5 2009/09/29 15:06:07 fdupont Exp */
23 #include <sys/types.h>
24 #include <sys/socket.h>
26 #include <netinet/in.h>
28 #include <arpa/inet.h>
37 #include <isc/buffer.h>
41 #include <isc/parseint.h>
42 #include <isc/sockaddr.h>
45 #include <dns/callbacks.h>
46 #include <dns/client.h>
47 #include <dns/fixedname.h>
50 #include <dns/rdata.h>
51 #include <dns/rdataclass.h>
52 #include <dns/rdatalist.h>
53 #include <dns/rdataset.h>
54 #include <dns/rdatastruct.h>
55 #include <dns/rdatatype.h>
56 #include <dns/result.h>
57 #include <dns/secalg.h>
62 static dns_tsec_t
*tsec
= NULL
;
63 static const dns_rdataclass_t default_rdataclass
= dns_rdataclass_in
;
64 static isc_bufferlist_t usedbuffers
;
65 static ISC_LIST(dns_rdatalist_t
) usedrdatalists
;
67 static void setup_tsec(char *keyfile
, isc_mem_t
*mctx
);
68 static void update_addordelete(isc_mem_t
*mctx
, char *cmdline
,
69 isc_boolean_t isdelete
, dns_name_t
*name
);
70 static void evaluate_prereq(isc_mem_t
*mctx
, char *cmdline
, dns_name_t
*name
);
72 ISC_PLATFORM_NORETURN_PRE
static void
73 usage(void) ISC_PLATFORM_NORETURN_POST
;
77 fprintf(stderr
, "sample-update "
81 "[-r recursive_server] "
83 "(add|delete) \"name TTL RRtype RDATA\"\n");
88 main(int argc
, char *argv
[]) {
90 struct addrinfo hints
, *res
;
92 dns_client_t
*client
= NULL
;
93 char *zonenamestr
= NULL
;
94 char *keyfilename
= NULL
;
95 char *prereqstr
= NULL
;
96 isc_sockaddrlist_t auth_servers
;
97 char *auth_server
= NULL
;
98 char *recursive_server
= NULL
;
99 isc_sockaddr_t sa_auth
, sa_recursive
;
100 isc_sockaddrlist_t rec_servers
;
102 isc_boolean_t isdelete
;
103 isc_buffer_t b
, *buf
;
104 dns_fixedname_t zname0
, pname0
, uname0
;
106 dns_name_t
*zname
= NULL
, *uname
, *pname
;
107 dns_rdataset_t
*rdataset
;
108 dns_rdatalist_t
*rdatalist
;
110 dns_namelist_t updatelist
, prereqlist
, *prereqlistp
= NULL
;
111 isc_mem_t
*umctx
= NULL
;
113 while ((ch
= getopt(argc
, argv
, "a:k:p:r:z:")) != -1) {
116 keyfilename
= optarg
;
119 auth_server
= optarg
;
125 recursive_server
= optarg
;
128 zonenamestr
= optarg
;
140 /* command line argument validation */
141 if (strcmp(argv
[0], "delete") == 0)
143 else if (strcmp(argv
[0], "add") == 0)
144 isdelete
= ISC_FALSE
;
146 fprintf(stderr
, "invalid update command: %s\n", argv
[0]);
150 if (auth_server
== NULL
&& recursive_server
== NULL
) {
151 fprintf(stderr
, "authoritative or recursive server "
152 "must be specified\n");
157 ISC_LIST_INIT(usedbuffers
);
158 ISC_LIST_INIT(usedrdatalists
);
159 ISC_LIST_INIT(prereqlist
);
160 ISC_LIST_INIT(auth_servers
);
162 result
= dns_lib_init();
163 if (result
!= ISC_R_SUCCESS
) {
164 fprintf(stderr
, "dns_lib_init failed: %d\n", result
);
167 result
= isc_mem_create(0, 0, &umctx
);
168 if (result
!= ISC_R_SUCCESS
) {
169 fprintf(stderr
, "failed to crate mctx\n");
173 result
= dns_client_create(&client
, 0);
174 if (result
!= ISC_R_SUCCESS
) {
175 fprintf(stderr
, "dns_client_create failed: %d\n", result
);
179 /* Set the authoritative server */
180 if (auth_server
!= NULL
) {
181 memset(&hints
, 0, sizeof(hints
));
182 hints
.ai_family
= AF_UNSPEC
;
183 hints
.ai_socktype
= SOCK_DGRAM
;
184 hints
.ai_protocol
= IPPROTO_UDP
;
185 hints
.ai_flags
= AI_NUMERICHOST
;
186 gai_error
= getaddrinfo(auth_server
, "53", &hints
, &res
);
187 if (gai_error
!= 0) {
188 fprintf(stderr
, "getaddrinfo failed: %s\n",
189 gai_strerror(gai_error
));
192 INSIST(res
->ai_addrlen
<= sizeof(sa_auth
.type
));
193 memcpy(&sa_auth
.type
, res
->ai_addr
, res
->ai_addrlen
);
195 sa_auth
.length
= res
->ai_addrlen
;
196 ISC_LINK_INIT(&sa_auth
, link
);
198 ISC_LIST_APPEND(auth_servers
, &sa_auth
, link
);
201 /* Set the recursive server */
202 if (recursive_server
!= NULL
) {
203 memset(&hints
, 0, sizeof(hints
));
204 hints
.ai_family
= AF_UNSPEC
;
205 hints
.ai_socktype
= SOCK_DGRAM
;
206 hints
.ai_protocol
= IPPROTO_UDP
;
207 hints
.ai_flags
= AI_NUMERICHOST
;
208 gai_error
= getaddrinfo(recursive_server
, "53", &hints
, &res
);
209 if (gai_error
!= 0) {
210 fprintf(stderr
, "getaddrinfo failed: %s\n",
211 gai_strerror(gai_error
));
214 INSIST(res
->ai_addrlen
<= sizeof(sa_recursive
.type
));
215 memcpy(&sa_recursive
.type
, res
->ai_addr
, res
->ai_addrlen
);
217 sa_recursive
.length
= res
->ai_addrlen
;
218 ISC_LINK_INIT(&sa_recursive
, link
);
219 ISC_LIST_INIT(rec_servers
);
220 ISC_LIST_APPEND(rec_servers
, &sa_recursive
, link
);
221 result
= dns_client_setservers(client
, dns_rdataclass_in
,
223 if (result
!= ISC_R_SUCCESS
) {
224 fprintf(stderr
, "set server failed: %d\n", result
);
229 /* Construct zone name */
231 if (zonenamestr
!= NULL
) {
232 namelen
= strlen(zonenamestr
);
233 isc_buffer_init(&b
, zonenamestr
, namelen
);
234 isc_buffer_add(&b
, namelen
);
235 dns_fixedname_init(&zname0
);
236 zname
= dns_fixedname_name(&zname0
);
237 result
= dns_name_fromtext(zname
, &b
, dns_rootname
, 0, NULL
);
238 if (result
!= ISC_R_SUCCESS
)
239 fprintf(stderr
, "failed to convert zone name: %d\n",
243 /* Construct prerequisite name (if given) */
244 if (prereqstr
!= NULL
) {
245 dns_fixedname_init(&pname0
);
246 pname
= dns_fixedname_name(&pname0
);
247 evaluate_prereq(umctx
, prereqstr
, pname
);
248 ISC_LIST_APPEND(prereqlist
, pname
, link
);
249 prereqlistp
= &prereqlist
;
252 /* Construct update name */
253 ISC_LIST_INIT(updatelist
);
254 dns_fixedname_init(&uname0
);
255 uname
= dns_fixedname_name(&uname0
);
256 update_addordelete(umctx
, argv
[1], isdelete
, uname
);
257 ISC_LIST_APPEND(updatelist
, uname
, link
);
259 /* Set up TSIG/SIG(0) key (if given) */
260 if (keyfilename
!= NULL
)
261 setup_tsec(keyfilename
, umctx
);
264 result
= dns_client_update(client
,
265 default_rdataclass
, /* XXX: fixed */
266 zname
, prereqlistp
, &updatelist
,
267 (auth_server
== NULL
) ? NULL
:
268 &auth_servers
, tsec
, 0);
269 if (result
!= ISC_R_SUCCESS
) {
271 "update failed: %s\n", dns_result_totext(result
));
273 fprintf(stderr
, "update succeeded\n");
276 while ((pname
= ISC_LIST_HEAD(prereqlist
)) != NULL
) {
277 while ((rdataset
= ISC_LIST_HEAD(pname
->list
)) != NULL
) {
278 ISC_LIST_UNLINK(pname
->list
, rdataset
, link
);
279 dns_rdataset_disassociate(rdataset
);
280 isc_mem_put(umctx
, rdataset
, sizeof(*rdataset
));
282 ISC_LIST_UNLINK(prereqlist
, pname
, link
);
284 while ((uname
= ISC_LIST_HEAD(updatelist
)) != NULL
) {
285 while ((rdataset
= ISC_LIST_HEAD(uname
->list
)) != NULL
) {
286 ISC_LIST_UNLINK(uname
->list
, rdataset
, link
);
287 dns_rdataset_disassociate(rdataset
);
288 isc_mem_put(umctx
, rdataset
, sizeof(*rdataset
));
290 ISC_LIST_UNLINK(updatelist
, uname
, link
);
292 while ((rdatalist
= ISC_LIST_HEAD(usedrdatalists
)) != NULL
) {
293 while ((rdata
= ISC_LIST_HEAD(rdatalist
->rdata
)) != NULL
) {
294 ISC_LIST_UNLINK(rdatalist
->rdata
, rdata
, link
);
295 isc_mem_put(umctx
, rdata
, sizeof(*rdata
));
297 ISC_LIST_UNLINK(usedrdatalists
, rdatalist
, link
);
298 isc_mem_put(umctx
, rdatalist
, sizeof(*rdatalist
));
300 while ((buf
= ISC_LIST_HEAD(usedbuffers
)) != NULL
) {
301 ISC_LIST_UNLINK(usedbuffers
, buf
, link
);
302 isc_buffer_free(&buf
);
305 dns_tsec_destroy(&tsec
);
306 isc_mem_destroy(&umctx
);
307 dns_client_destroy(&client
);
314 * Subroutines borrowed from nsupdate.c
316 #define MAXWIRE (64 * 1024)
317 #define TTL_MAX 2147483647U /* Maximum signed 32 bit integer. */
320 nsu_strsep(char **stringp
, const char *delim
) {
321 char *string
= *stringp
;
329 for (; *string
!= '\0'; string
++) {
331 for (d
= delim
; (dc
= *d
) != '\0'; d
++) {
339 for (s
= string
; *s
!= '\0'; s
++) {
341 for (d
= delim
; (dc
= *d
) != '\0'; d
++) {
354 fatal(const char *format
, ...) {
357 va_start(args
, format
);
358 vfprintf(stderr
, format
, args
);
360 fprintf(stderr
, "\n");
365 check_result(isc_result_t result
, const char *msg
) {
366 if (result
!= ISC_R_SUCCESS
)
367 fatal("%s: %s", msg
, isc_result_totext(result
));
371 parse_name(char **cmdlinep
, dns_name_t
*name
) {
376 word
= nsu_strsep(cmdlinep
, " \t\r\n");
378 fprintf(stderr
, "could not read owner name\n");
382 isc_buffer_init(&source
, word
, strlen(word
));
383 isc_buffer_add(&source
, strlen(word
));
384 result
= dns_name_fromtext(name
, &source
, dns_rootname
, 0, NULL
);
385 check_result(result
, "dns_name_fromtext");
386 isc_buffer_invalidate(&source
);
390 parse_rdata(isc_mem_t
*mctx
, char **cmdlinep
, dns_rdataclass_t rdataclass
,
391 dns_rdatatype_t rdatatype
, dns_rdata_t
*rdata
)
393 char *cmdline
= *cmdlinep
;
394 isc_buffer_t source
, *buf
= NULL
, *newbuf
= NULL
;
396 isc_lex_t
*lex
= NULL
;
397 dns_rdatacallbacks_t callbacks
;
400 while (cmdline
!= NULL
&& *cmdline
!= 0 &&
401 isspace((unsigned char)*cmdline
))
404 if (cmdline
!= NULL
&& *cmdline
!= 0) {
405 dns_rdatacallbacks_init(&callbacks
);
406 result
= isc_lex_create(mctx
, strlen(cmdline
), &lex
);
407 check_result(result
, "isc_lex_create");
408 isc_buffer_init(&source
, cmdline
, strlen(cmdline
));
409 isc_buffer_add(&source
, strlen(cmdline
));
410 result
= isc_lex_openbuffer(lex
, &source
);
411 check_result(result
, "isc_lex_openbuffer");
412 result
= isc_buffer_allocate(mctx
, &buf
, MAXWIRE
);
413 check_result(result
, "isc_buffer_allocate");
414 result
= dns_rdata_fromtext(rdata
, rdataclass
, rdatatype
, lex
,
415 dns_rootname
, 0, mctx
, buf
,
417 isc_lex_destroy(&lex
);
418 if (result
== ISC_R_SUCCESS
) {
419 isc_buffer_usedregion(buf
, &r
);
420 result
= isc_buffer_allocate(mctx
, &newbuf
, r
.length
);
421 check_result(result
, "isc_buffer_allocate");
422 isc_buffer_putmem(newbuf
, r
.base
, r
.length
);
423 isc_buffer_usedregion(newbuf
, &r
);
424 dns_rdata_reset(rdata
);
425 dns_rdata_fromregion(rdata
, rdataclass
, rdatatype
, &r
);
426 isc_buffer_free(&buf
);
427 ISC_LIST_APPEND(usedbuffers
, newbuf
, link
);
429 fprintf(stderr
, "invalid rdata format: %s\n",
430 isc_result_totext(result
));
431 isc_buffer_free(&buf
);
435 rdata
->flags
= DNS_RDATA_UPDATE
;
441 update_addordelete(isc_mem_t
*mctx
, char *cmdline
, isc_boolean_t isdelete
,
447 dns_rdataclass_t rdataclass
;
448 dns_rdatatype_t rdatatype
;
449 dns_rdata_t
*rdata
= NULL
;
450 dns_rdatalist_t
*rdatalist
= NULL
;
451 dns_rdataset_t
*rdataset
= NULL
;
452 isc_textregion_t region
;
455 * Read the owner name.
457 parse_name(&cmdline
, name
);
459 rdata
= isc_mem_get(mctx
, sizeof(*rdata
));
461 fprintf(stderr
, "memory allocation for rdata failed\n");
464 dns_rdata_init(rdata
);
467 * If this is an add, read the TTL and verify that it's in range.
468 * If it's a delete, ignore a TTL if present (for compatibility).
470 word
= nsu_strsep(&cmdline
, " \t\r\n");
471 if (word
== NULL
|| *word
== 0) {
473 fprintf(stderr
, "could not read owner ttl\n");
478 rdataclass
= dns_rdataclass_any
;
479 rdatatype
= dns_rdatatype_any
;
480 rdata
->flags
= DNS_RDATA_UPDATE
;
484 result
= isc_parse_uint32(&ttl
, word
, 10);
485 if (result
!= ISC_R_SUCCESS
) {
490 fprintf(stderr
, "ttl '%s': %s\n", word
,
491 isc_result_totext(result
));
498 else if (ttl
> TTL_MAX
) {
499 fprintf(stderr
, "ttl '%s' is out of range (0 to %u)\n",
505 * Read the class or type.
507 word
= nsu_strsep(&cmdline
, " \t\r\n");
509 if (word
== NULL
|| *word
== 0) {
511 rdataclass
= dns_rdataclass_any
;
512 rdatatype
= dns_rdatatype_any
;
513 rdata
->flags
= DNS_RDATA_UPDATE
;
516 fprintf(stderr
, "could not read class or type\n");
521 region
.length
= strlen(word
);
522 result
= dns_rdataclass_fromtext(&rdataclass
, ®ion
);
523 if (result
== ISC_R_SUCCESS
) {
527 word
= nsu_strsep(&cmdline
, " \t\r\n");
528 if (word
== NULL
|| *word
== 0) {
530 rdataclass
= dns_rdataclass_any
;
531 rdatatype
= dns_rdatatype_any
;
532 rdata
->flags
= DNS_RDATA_UPDATE
;
535 fprintf(stderr
, "could not read type\n");
540 region
.length
= strlen(word
);
541 result
= dns_rdatatype_fromtext(&rdatatype
, ®ion
);
542 if (result
!= ISC_R_SUCCESS
) {
543 fprintf(stderr
, "'%s' is not a valid type: %s\n",
544 word
, isc_result_totext(result
));
548 rdataclass
= default_rdataclass
;
549 result
= dns_rdatatype_fromtext(&rdatatype
, ®ion
);
550 if (result
!= ISC_R_SUCCESS
) {
551 fprintf(stderr
, "'%s' is not a valid class or type: "
552 "%s\n", word
, isc_result_totext(result
));
557 parse_rdata(mctx
, &cmdline
, rdataclass
, rdatatype
, rdata
);
560 if ((rdata
->flags
& DNS_RDATA_UPDATE
) != 0)
561 rdataclass
= dns_rdataclass_any
;
563 rdataclass
= dns_rdataclass_none
;
565 if ((rdata
->flags
& DNS_RDATA_UPDATE
) != 0) {
566 fprintf(stderr
, "could not read rdata\n");
573 rdatalist
= isc_mem_get(mctx
, sizeof(*rdatalist
));
574 if (rdatalist
== NULL
) {
575 fprintf(stderr
, "memory allocation for rdatalist failed\n");
578 dns_rdatalist_init(rdatalist
);
579 rdatalist
->type
= rdatatype
;
580 rdatalist
->rdclass
= rdataclass
;
581 rdatalist
->covers
= rdatatype
;
582 rdatalist
->ttl
= (dns_ttl_t
)ttl
;
583 ISC_LIST_INIT(rdatalist
->rdata
);
584 ISC_LIST_APPEND(rdatalist
->rdata
, rdata
, link
);
585 ISC_LIST_APPEND(usedrdatalists
, rdatalist
, link
);
587 rdataset
= isc_mem_get(mctx
, sizeof(*rdataset
));
588 if (rdataset
== NULL
) {
589 fprintf(stderr
, "memory allocation for rdataset failed\n");
592 dns_rdataset_init(rdataset
);
593 dns_rdatalist_tordataset(rdatalist
, rdataset
);
594 ISC_LIST_INIT(name
->list
);
595 ISC_LIST_APPEND(name
->list
, rdataset
, link
);
599 make_prereq(isc_mem_t
*mctx
, char *cmdline
, isc_boolean_t ispositive
,
600 isc_boolean_t isrrset
, dns_name_t
*name
)
604 isc_textregion_t region
;
605 dns_rdataset_t
*rdataset
= NULL
;
606 dns_rdatalist_t
*rdatalist
= NULL
;
607 dns_rdataclass_t rdataclass
;
608 dns_rdatatype_t rdatatype
;
609 dns_rdata_t
*rdata
= NULL
;
612 * Read the owner name
614 parse_name(&cmdline
, name
);
617 * If this is an rrset prereq, read the class or type.
620 word
= nsu_strsep(&cmdline
, " \t\r\n");
621 if (word
== NULL
|| *word
== 0) {
622 fprintf(stderr
, "could not read class or type\n");
626 region
.length
= strlen(word
);
627 result
= dns_rdataclass_fromtext(&rdataclass
, ®ion
);
628 if (result
== ISC_R_SUCCESS
) {
632 word
= nsu_strsep(&cmdline
, " \t\r\n");
633 if (word
== NULL
|| *word
== 0) {
634 fprintf(stderr
, "could not read type\n");
638 region
.length
= strlen(word
);
639 result
= dns_rdatatype_fromtext(&rdatatype
, ®ion
);
640 if (result
!= ISC_R_SUCCESS
) {
641 fprintf(stderr
, "invalid type: %s\n", word
);
645 rdataclass
= default_rdataclass
;
646 result
= dns_rdatatype_fromtext(&rdatatype
, ®ion
);
647 if (result
!= ISC_R_SUCCESS
) {
648 fprintf(stderr
, "invalid type: %s\n", word
);
653 rdatatype
= dns_rdatatype_any
;
655 rdata
= isc_mem_get(mctx
, sizeof(*rdata
));
657 fprintf(stderr
, "memory allocation for rdata failed\n");
660 dns_rdata_init(rdata
);
662 if (isrrset
&& ispositive
)
663 parse_rdata(mctx
, &cmdline
, rdataclass
, rdatatype
, rdata
);
665 rdata
->flags
= DNS_RDATA_UPDATE
;
667 rdatalist
= isc_mem_get(mctx
, sizeof(*rdatalist
));
668 if (rdatalist
== NULL
) {
669 fprintf(stderr
, "memory allocation for rdatalist failed\n");
672 dns_rdatalist_init(rdatalist
);
673 rdatalist
->type
= rdatatype
;
675 if (isrrset
&& rdata
->data
!= NULL
)
676 rdatalist
->rdclass
= rdataclass
;
678 rdatalist
->rdclass
= dns_rdataclass_any
;
680 rdatalist
->rdclass
= dns_rdataclass_none
;
681 rdatalist
->covers
= 0;
683 rdata
->rdclass
= rdatalist
->rdclass
;
684 rdata
->type
= rdatatype
;
685 ISC_LIST_INIT(rdatalist
->rdata
);
686 ISC_LIST_APPEND(rdatalist
->rdata
, rdata
, link
);
687 ISC_LIST_APPEND(usedrdatalists
, rdatalist
, link
);
689 rdataset
= isc_mem_get(mctx
, sizeof(*rdataset
));
690 if (rdataset
== NULL
) {
691 fprintf(stderr
, "memory allocation for rdataset failed\n");
694 dns_rdataset_init(rdataset
);
695 dns_rdatalist_tordataset(rdatalist
, rdataset
);
696 ISC_LIST_INIT(name
->list
);
697 ISC_LIST_APPEND(name
->list
, rdataset
, link
);
701 evaluate_prereq(isc_mem_t
*mctx
, char *cmdline
, dns_name_t
*name
) {
703 isc_boolean_t ispositive
, isrrset
;
705 word
= nsu_strsep(&cmdline
, " \t\r\n");
706 if (word
== NULL
|| *word
== 0) {
707 fprintf(stderr
, "could not read operation code\n");
710 if (strcasecmp(word
, "nxdomain") == 0) {
711 ispositive
= ISC_FALSE
;
713 } else if (strcasecmp(word
, "yxdomain") == 0) {
714 ispositive
= ISC_TRUE
;
716 } else if (strcasecmp(word
, "nxrrset") == 0) {
717 ispositive
= ISC_FALSE
;
719 } else if (strcasecmp(word
, "yxrrset") == 0) {
720 ispositive
= ISC_TRUE
;
723 fprintf(stderr
, "incorrect operation code: %s\n", word
);
727 make_prereq(mctx
, cmdline
, ispositive
, isrrset
, name
);
731 setup_tsec(char *keyfile
, isc_mem_t
*mctx
) {
732 dst_key_t
*dstkey
= NULL
;
734 dns_tsectype_t tsectype
;
736 result
= dst_key_fromnamedfile(keyfile
, NULL
,
737 DST_TYPE_PRIVATE
| DST_TYPE_KEY
, mctx
,
739 if (result
!= ISC_R_SUCCESS
) {
740 fprintf(stderr
, "could not read key from %s: %s\n",
741 keyfile
, isc_result_totext(result
));
745 if (dst_key_alg(dstkey
) == DST_ALG_HMACMD5
)
746 tsectype
= dns_tsectype_tsig
;
748 tsectype
= dns_tsectype_sig0
;
750 result
= dns_tsec_create(mctx
, tsectype
, dstkey
, &tsec
);
751 if (result
!= ISC_R_SUCCESS
) {
752 fprintf(stderr
, "could not create tsec: %s\n",
753 isc_result_totext(result
));