4 * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000, 2001, 2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: dnssectool.c,v 1.58 2009/10/26 23:47:35 tbox Exp */
25 * DNSSEC Support Routines.
32 #include <isc/buffer.h>
34 #include <isc/entropy.h>
37 #include <isc/string.h>
40 #include <isc/print.h>
44 #include <dns/rdatastruct.h>
45 #include <dns/rdataclass.h>
46 #include <dns/rdatatype.h>
47 #include <dns/result.h>
48 #include <dns/secalg.h>
51 #include "dnssectool.h"
54 extern const char *program
;
56 typedef struct entropysource entropysource_t
;
58 struct entropysource
{
59 isc_entropysource_t
*source
;
61 ISC_LINK(entropysource_t
) link
;
64 static ISC_LIST(entropysource_t
) sources
;
65 static fatalcallback_t
*fatalcallback
= NULL
;
68 fatal(const char *format
, ...) {
71 fprintf(stderr
, "%s: fatal: ", program
);
72 va_start(args
, format
);
73 vfprintf(stderr
, format
, args
);
75 fprintf(stderr
, "\n");
76 if (fatalcallback
!= NULL
)
82 setfatalcallback(fatalcallback_t
*callback
) {
83 fatalcallback
= callback
;
87 check_result(isc_result_t result
, const char *message
) {
88 if (result
!= ISC_R_SUCCESS
)
89 fatal("%s: %s", message
, isc_result_totext(result
));
93 vbprintf(int level
, const char *fmt
, ...) {
98 fprintf(stderr
, "%s: ", program
);
99 vfprintf(stderr
, fmt
, ap
);
104 type_format(const dns_rdatatype_t type
, char *cp
, unsigned int size
) {
109 isc_buffer_init(&b
, cp
, size
- 1);
110 result
= dns_rdatatype_totext(type
, &b
);
111 check_result(result
, "dns_rdatatype_totext()");
112 isc_buffer_usedregion(&b
, &r
);
113 r
.base
[r
.length
] = 0;
117 sig_format(dns_rdata_rrsig_t
*sig
, char *cp
, unsigned int size
) {
118 char namestr
[DNS_NAME_FORMATSIZE
];
119 char algstr
[DNS_NAME_FORMATSIZE
];
121 dns_name_format(&sig
->signer
, namestr
, sizeof(namestr
));
122 dns_secalg_format(sig
->algorithm
, algstr
, sizeof(algstr
));
123 snprintf(cp
, size
, "%s/%s/%d", namestr
, algstr
, sig
->keyid
);
127 setup_logging(int verbose
, isc_mem_t
*mctx
, isc_log_t
**logp
) {
129 isc_logdestination_t destination
;
130 isc_logconfig_t
*logconfig
= NULL
;
131 isc_log_t
*log
= NULL
;
139 * We want to see warnings about things like out-of-zone
140 * data in the master file even when not verbose.
142 level
= ISC_LOG_WARNING
;
145 level
= ISC_LOG_INFO
;
148 level
= ISC_LOG_DEBUG(verbose
- 2 + 1);
152 RUNTIME_CHECK(isc_log_create(mctx
, &log
, &logconfig
) == ISC_R_SUCCESS
);
153 isc_log_setcontext(log
);
155 dns_log_setcontext(log
);
157 RUNTIME_CHECK(isc_log_settag(logconfig
, program
) == ISC_R_SUCCESS
);
160 * Set up a channel similar to default_stderr except:
161 * - the logging level is passed in
162 * - the program name and logging level are printed
163 * - no time stamp is printed
165 destination
.file
.stream
= stderr
;
166 destination
.file
.name
= NULL
;
167 destination
.file
.versions
= ISC_LOG_ROLLNEVER
;
168 destination
.file
.maximum_size
= 0;
169 result
= isc_log_createchannel(logconfig
, "stderr",
173 ISC_LOG_PRINTTAG
|ISC_LOG_PRINTLEVEL
);
174 check_result(result
, "isc_log_createchannel()");
176 RUNTIME_CHECK(isc_log_usechannel(logconfig
, "stderr",
177 NULL
, NULL
) == ISC_R_SUCCESS
);
183 cleanup_logging(isc_log_t
**logp
) {
186 REQUIRE(logp
!= NULL
);
191 isc_log_destroy(&log
);
192 isc_log_setcontext(NULL
);
193 dns_log_setcontext(NULL
);
198 setup_entropy(isc_mem_t
*mctx
, const char *randomfile
, isc_entropy_t
**ectx
) {
200 isc_entropysource_t
*source
= NULL
;
201 entropysource_t
*elt
;
202 int usekeyboard
= ISC_ENTROPY_KEYBOARDMAYBE
;
204 REQUIRE(ectx
!= NULL
);
207 result
= isc_entropy_create(mctx
, ectx
);
208 if (result
!= ISC_R_SUCCESS
)
209 fatal("could not create entropy object");
210 ISC_LIST_INIT(sources
);
213 if (randomfile
!= NULL
&& strcmp(randomfile
, "keyboard") == 0) {
214 usekeyboard
= ISC_ENTROPY_KEYBOARDYES
;
218 result
= isc_entropy_usebestsource(*ectx
, &source
, randomfile
,
221 if (result
!= ISC_R_SUCCESS
)
222 fatal("could not initialize entropy source: %s",
223 isc_result_totext(result
));
225 if (source
!= NULL
) {
226 elt
= isc_mem_get(mctx
, sizeof(*elt
));
228 fatal("out of memory");
229 elt
->source
= source
;
231 ISC_LINK_INIT(elt
, link
);
232 ISC_LIST_APPEND(sources
, elt
, link
);
237 cleanup_entropy(isc_entropy_t
**ectx
) {
238 entropysource_t
*source
;
239 while (!ISC_LIST_EMPTY(sources
)) {
240 source
= ISC_LIST_HEAD(sources
);
241 ISC_LIST_UNLINK(sources
, source
, link
);
242 isc_entropy_destroysource(&source
->source
);
243 isc_mem_put(source
->mctx
, source
, sizeof(*source
));
245 isc_entropy_detach(ectx
);
249 time_units(isc_stdtime_t offset
, char *suffix
, const char *str
) {
252 return (offset
* (365 * 24 * 3600));
256 return (offset
* (30 * 24 * 3600));
258 return (offset
* 60);
260 fatal("'%s' ambiguous: use 'mi' for minutes "
261 "or 'mo' for months", str
);
263 fatal("time value %s is invalid", str
);
268 return (offset
* (7 * 24 * 3600));
270 return (offset
* (24 * 3600));
272 return (offset
* 3600);
273 case 'S': case 's': case '\0':
276 fatal("time value %s is invalid", str
);
279 return(0); /* silence compiler warning */
283 strtottl(const char *str
) {
284 const char *orig
= str
;
288 ttl
= strtol(str
, &endp
, 0);
289 if (ttl
== 0 && endp
== str
)
290 fatal("TTL must be numeric");
291 ttl
= time_units(ttl
, endp
, orig
);
296 strtotime(const char *str
, isc_int64_t now
, isc_int64_t base
) {
297 isc_int64_t val
, offset
;
299 const char *orig
= str
;
302 if ((str
[0] == '0' || str
[0] == '-') && str
[1] == '\0')
303 return ((isc_stdtime_t
) 0);
305 if (strncmp(str
, "now", 3) == 0) {
311 return ((isc_stdtime_t
) base
);
312 else if (str
[0] == '+') {
313 offset
= strtol(str
+ 1, &endp
, 0);
314 offset
= time_units((isc_stdtime_t
) offset
, endp
, orig
);
316 } else if (str
[0] == '-') {
317 offset
= strtol(str
+ 1, &endp
, 0);
318 offset
= time_units((isc_stdtime_t
) offset
, endp
, orig
);
320 } else if (strlen(str
) == 8U) {
322 sprintf(timestr
, "%s000000", str
);
323 result
= dns_time64_fromtext(timestr
, &val
);
324 if (result
!= ISC_R_SUCCESS
)
325 fatal("time value %s is invalid: %s", orig
,
326 isc_result_totext(result
));
327 } else if (strlen(str
) > 14U) {
328 fatal("time value %s is invalid", orig
);
330 result
= dns_time64_fromtext(str
, &val
);
331 if (result
!= ISC_R_SUCCESS
)
332 fatal("time value %s is invalid: %s", orig
,
333 isc_result_totext(result
));
336 return ((isc_stdtime_t
) val
);
340 strtoclass(const char *str
) {
342 dns_rdataclass_t rdclass
;
346 return dns_rdataclass_in
;
347 DE_CONST(str
, r
.base
);
348 r
.length
= strlen(str
);
349 ret
= dns_rdataclass_fromtext(&rdclass
, &r
);
350 if (ret
!= ISC_R_SUCCESS
)
351 fatal("unknown class %s", str
);
356 try_dir(const char *dirname
) {
361 result
= isc_dir_open(&d
, dirname
);
362 if (result
== ISC_R_SUCCESS
) {
369 * Check private key version compatibility.
372 check_keyversion(dst_key_t
*key
, char *keystr
) {
374 dst_key_getprivateformat(key
, &major
, &minor
);
375 INSIST(major
<= DST_MAJOR_VERSION
); /* invalid private key */
377 if (major
< DST_MAJOR_VERSION
|| minor
< DST_MINOR_VERSION
)
378 fatal("Key %s has incompatible format version %d.%d, "
379 "use -f to force upgrade to new version.",
380 keystr
, major
, minor
);
381 if (minor
> DST_MINOR_VERSION
)
382 fatal("Key %s has incompatible format version %d.%d, "
383 "use -f to force downgrade to current version.",
384 keystr
, major
, minor
);
388 set_keyversion(dst_key_t
*key
) {
390 dst_key_getprivateformat(key
, &major
, &minor
);
391 INSIST(major
<= DST_MAJOR_VERSION
);
393 if (major
!= DST_MAJOR_VERSION
|| minor
!= DST_MINOR_VERSION
)
394 dst_key_setprivateformat(key
, DST_MAJOR_VERSION
,
398 * If the key is from a version older than 1.3, set
399 * set the creation date
401 if (major
< 1 || (major
== 1 && minor
<= 2)) {
403 isc_stdtime_get(&now
);
404 dst_key_settime(key
, DST_TIME_CREATED
, now
);