Home | History | Annotate | Line # | Download | only in resolv
res_debug.c revision 1.14
      1 /*	$NetBSD: res_debug.c,v 1.14 2015/02/24 17:56:20 christos Exp $	*/
      2 
      3 /*
      4  * Portions Copyright (C) 2004, 2005, 2008, 2009  Internet Systems Consortium, Inc. ("ISC")
      5  * Portions Copyright (C) 1996-2003  Internet Software Consortium.
      6  *
      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.
     10  *
     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.
     18  */
     19 
     20 /*
     21  * Copyright (c) 1985
     22  *    The Regents of the University of California.  All rights reserved.
     23  *
     24  * Redistribution and use in source and binary forms, with or without
     25  * modification, are permitted provided that the following conditions
     26  * are met:
     27  * 1. Redistributions of source code must retain the above copyright
     28  *    notice, this list of conditions and the following disclaimer.
     29  * 2. Redistributions in binary form must reproduce the above copyright
     30  *    notice, this list of conditions and the following disclaimer in the
     31  *    documentation and/or other materials provided with the distribution.
     32  * 3. Neither the name of the University nor the names of its contributors
     33  *    may be used to endorse or promote products derived from this software
     34  *    without specific prior written permission.
     35  *
     36  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     37  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     38  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     39  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     40  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     41  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     42  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     43  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     44  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     45  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     46  * SUCH DAMAGE.
     47  */
     48 
     49 /*
     50  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
     51  *
     52  * Permission to use, copy, modify, and distribute this software for any
     53  * purpose with or without fee is hereby granted, provided that the above
     54  * copyright notice and this permission notice appear in all copies, and that
     55  * the name of Digital Equipment Corporation not be used in advertising or
     56  * publicity pertaining to distribution of the document or software without
     57  * specific, written prior permission.
     58  *
     59  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
     60  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
     61  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
     62  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
     63  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
     64  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
     65  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
     66  * SOFTWARE.
     67  */
     68 
     69 /*
     70  * Portions Copyright (c) 1995 by International Business Machines, Inc.
     71  *
     72  * International Business Machines, Inc. (hereinafter called IBM) grants
     73  * permission under its copyrights to use, copy, modify, and distribute this
     74  * Software with or without fee, provided that the above copyright notice and
     75  * all paragraphs of this notice appear in all copies, and that the name of IBM
     76  * not be used in connection with the marketing of any product incorporating
     77  * the Software or modifications thereof, without specific, written prior
     78  * permission.
     79  *
     80  * To the extent it has a right to do so, IBM grants an immunity from suit
     81  * under its patents, if any, for the use, sale or manufacture of products to
     82  * the extent that such products are used for performing Domain Name System
     83  * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
     84  * granted for any product per se or for any other function of any product.
     85  *
     86  * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
     87  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
     88  * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
     89  * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
     90  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
     91  * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
     92  */
     93 
     94 #include <sys/cdefs.h>
     95 #if defined(LIBC_SCCS) && !defined(lint)
     96 #ifdef notdef
     97 static const char sccsid[] = "@(#)res_debug.c	8.1 (Berkeley) 6/4/93";
     98 static const char rcsid[] = "Id: res_debug.c,v 1.19 2009/02/26 11:20:20 tbox Exp";
     99 #else
    100 __RCSID("$NetBSD: res_debug.c,v 1.14 2015/02/24 17:56:20 christos Exp $");
    101 #endif
    102 #endif /* LIBC_SCCS and not lint */
    103 
    104 #include "port_before.h"
    105 
    106 #include "namespace.h"
    107 #include <sys/types.h>
    108 #include <sys/param.h>
    109 #include <sys/socket.h>
    110 
    111 #include <netinet/in.h>
    112 #include <arpa/inet.h>
    113 #include <arpa/nameser.h>
    114 
    115 #include <assert.h>
    116 #include <ctype.h>
    117 #include <errno.h>
    118 #include <math.h>
    119 #include <netdb.h>
    120 #include <resolv.h>
    121 #include <resolv_mt.h>
    122 #include <stdio.h>
    123 #include <stdlib.h>
    124 #include <string.h>
    125 #include <time.h>
    126 
    127 #include "port_after.h"
    128 
    129 #ifdef SPRINTF_CHAR
    130 # define SPRINTF(x) strlen(sprintf/**/x)
    131 #else
    132 # define SPRINTF(x) sprintf x
    133 #endif
    134 
    135 extern const char *_res_opcodes[];
    136 extern const char *_res_sectioncodes[];
    137 
    138 #if 0
    139 #ifdef __weak_alias
    140 __weak_alias(res_pquery,__res_pquery)
    141 __weak_alias(res_nametoclass,__res_nametoclass)
    142 __weak_alias(res_nametotype,__res_nametotype)
    143 #endif
    144 #endif
    145 
    146 #ifndef _LIBC
    147 /*%
    148  * Print the current options.
    149  */
    150 void
    151 fp_resstat(const res_state statp, FILE *file) {
    152 	u_long mask;
    153 
    154 	fprintf(file, ";; res options:");
    155 	for (mask = 1;  mask != 0U;  mask <<= 1)
    156 		if (statp->options & mask)
    157 			fprintf(file, " %s", p_option(mask));
    158 	putc('\n', file);
    159 }
    160 #endif
    161 
    162 static void
    163 do_section(const res_state statp,
    164 	   ns_msg *handle, ns_sect section,
    165 	   int pflag, FILE *file)
    166 {
    167 	int n, sflag, rrnum;
    168 	static int buflen = 2048;
    169 	char *buf;
    170 	ns_opcode opcode;
    171 	ns_rr rr;
    172 
    173 	/*
    174 	 * Print answer records.
    175 	 */
    176 	sflag = (int)(statp->pfcode & pflag);
    177 	if (statp->pfcode && !sflag)
    178 		return;
    179 
    180 	buf = malloc((size_t)buflen);
    181 	if (buf == NULL) {
    182 		fprintf(file, ";; memory allocation failure\n");
    183 		return;
    184 	}
    185 
    186 	opcode = (ns_opcode) ns_msg_getflag(*handle, ns_f_opcode);
    187 	rrnum = 0;
    188 	for (;;) {
    189 		if (ns_parserr(handle, section, rrnum, &rr)) {
    190 			if (errno != ENODEV)
    191 				fprintf(file, ";; ns_parserr: %s\n",
    192 					strerror(errno));
    193 			else if (rrnum > 0 && sflag != 0 &&
    194 				 (statp->pfcode & RES_PRF_HEAD1))
    195 				putc('\n', file);
    196 			goto cleanup;
    197 		}
    198 		if (rrnum == 0 && sflag != 0 && (statp->pfcode & RES_PRF_HEAD1))
    199 			fprintf(file, ";; %s SECTION:\n",
    200 				p_section(section, opcode));
    201 		if (section == ns_s_qd)
    202 			fprintf(file, ";;\t%s, type = %s, class = %s\n",
    203 				ns_rr_name(rr),
    204 				p_type(ns_rr_type(rr)),
    205 				p_class(ns_rr_class(rr)));
    206 		else if (section == ns_s_ar && ns_rr_type(rr) == ns_t_opt) {
    207 			size_t rdatalen, ttl;
    208 			uint16_t optcode, optlen;
    209 
    210 			rdatalen = ns_rr_rdlen(rr);
    211 			ttl = ns_rr_ttl(rr);
    212 
    213 			fprintf(file,
    214 				"; EDNS: version: %zu, udp=%u, flags=%04zx\n",
    215 				(ttl>>16)&0xff, ns_rr_class(rr), ttl&0xffff);
    216 
    217 			while (rdatalen >= 4) {
    218 				const u_char *cp = ns_rr_rdata(rr);
    219 				int i;
    220 
    221 				GETSHORT(optcode, cp);
    222 				GETSHORT(optlen, cp);
    223 
    224 				if (optcode == NS_OPT_NSID) {
    225 					fputs("; NSID: ", file);
    226 					if (optlen == 0) {
    227 						fputs("; NSID\n", file);
    228 					} else {
    229 						fputs("; NSID: ", file);
    230 						for (i = 0; i < optlen; i++)
    231 							fprintf(file, "%02x ",
    232 								cp[i]);
    233 						fputs(" (",file);
    234 						for (i = 0; i < optlen; i++)
    235 							fprintf(file, "%c",
    236 								isprint(cp[i])?
    237 								cp[i] : '.');
    238 						fputs(")\n", file);
    239 					}
    240 				} else {
    241 					if (optlen == 0) {
    242 						fprintf(file, "; OPT=%u\n",
    243 							optcode);
    244 					} else {
    245 						fprintf(file, "; OPT=%u: ",
    246 							optcode);
    247 						for (i = 0; i < optlen; i++)
    248 							fprintf(file, "%02x ",
    249 								cp[i]);
    250 						fputs(" (",file);
    251 						for (i = 0; i < optlen; i++)
    252 							fprintf(file, "%c",
    253 								isprint(cp[i]) ?
    254 									cp[i] : '.');
    255 						fputs(")\n", file);
    256 					}
    257 				}
    258 				rdatalen -= 4 + optlen;
    259 			}
    260 		} else {
    261 			n = ns_sprintrr(handle, &rr, NULL, NULL,
    262 					buf, (u_int)buflen);
    263 			if (n < 0) {
    264 				if (errno == ENOSPC) {
    265 					free(buf);
    266 					buf = NULL;
    267 					if (buflen < 131072)
    268 						buf = malloc((size_t)(buflen += 1024));
    269 					if (buf == NULL) {
    270 						fprintf(file,
    271 					      ";; memory allocation failure\n");
    272 					      return;
    273 					}
    274 					continue;
    275 				}
    276 				fprintf(file, ";; ns_sprintrr: %s\n",
    277 					strerror(errno));
    278 				goto cleanup;
    279 			}
    280 			fputs(buf, file);
    281 			fputc('\n', file);
    282 		}
    283 		rrnum++;
    284 	}
    285  cleanup:
    286 	if (buf != NULL)
    287 		free(buf);
    288 }
    289 
    290 /*%
    291  * Print the contents of a query.
    292  * This is intended to be primarily a debugging routine.
    293  */
    294 void
    295 res_pquery(const res_state statp, const u_char *msg, int len, FILE *file) {
    296 	ns_msg handle;
    297 	int qdcount, ancount, nscount, arcount;
    298 	u_int opcode, rcode, id;
    299 
    300 	if (ns_initparse(msg, len, &handle) < 0) {
    301 		fprintf(file, ";; ns_initparse: %s\n", strerror(errno));
    302 		return;
    303 	}
    304 	opcode = ns_msg_getflag(handle, ns_f_opcode);
    305 	rcode = ns_msg_getflag(handle, ns_f_rcode);
    306 	id = ns_msg_id(handle);
    307 	qdcount = ns_msg_count(handle, ns_s_qd);
    308 	ancount = ns_msg_count(handle, ns_s_an);
    309 	nscount = ns_msg_count(handle, ns_s_ns);
    310 	arcount = ns_msg_count(handle, ns_s_ar);
    311 
    312 	/*
    313 	 * Print header fields.
    314 	 */
    315 	if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEADX) || rcode)
    316 		fprintf(file,
    317 			";; ->>HEADER<<- opcode: %s, status: %s, id: %d\n",
    318 			_res_opcodes[opcode], p_rcode((int)rcode), id);
    319 	if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEADX))
    320 		putc(';', file);
    321 	if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEAD2)) {
    322 		fprintf(file, "; flags:");
    323 		if (ns_msg_getflag(handle, ns_f_qr))
    324 			fprintf(file, " qr");
    325 		if (ns_msg_getflag(handle, ns_f_aa))
    326 			fprintf(file, " aa");
    327 		if (ns_msg_getflag(handle, ns_f_tc))
    328 			fprintf(file, " tc");
    329 		if (ns_msg_getflag(handle, ns_f_rd))
    330 			fprintf(file, " rd");
    331 		if (ns_msg_getflag(handle, ns_f_ra))
    332 			fprintf(file, " ra");
    333 		if (ns_msg_getflag(handle, ns_f_z))
    334 			fprintf(file, " ??");
    335 		if (ns_msg_getflag(handle, ns_f_ad))
    336 			fprintf(file, " ad");
    337 		if (ns_msg_getflag(handle, ns_f_cd))
    338 			fprintf(file, " cd");
    339 	}
    340 	if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEAD1)) {
    341 		fprintf(file, "; %s: %d",
    342 			p_section(ns_s_qd, (int)opcode), qdcount);
    343 		fprintf(file, ", %s: %d",
    344 			p_section(ns_s_an, (int)opcode), ancount);
    345 		fprintf(file, ", %s: %d",
    346 			p_section(ns_s_ns, (int)opcode), nscount);
    347 		fprintf(file, ", %s: %d",
    348 			p_section(ns_s_ar, (int)opcode), arcount);
    349 	}
    350 	if ((!statp->pfcode) || (statp->pfcode &
    351 		(RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) {
    352 		putc('\n',file);
    353 	}
    354 	/*
    355 	 * Print the various sections.
    356 	 */
    357 	do_section(statp, &handle, ns_s_qd, RES_PRF_QUES, file);
    358 	do_section(statp, &handle, ns_s_an, RES_PRF_ANS, file);
    359 	do_section(statp, &handle, ns_s_ns, RES_PRF_AUTH, file);
    360 	do_section(statp, &handle, ns_s_ar, RES_PRF_ADD, file);
    361 	if (qdcount == 0 && ancount == 0 &&
    362 	    nscount == 0 && arcount == 0)
    363 		putc('\n', file);
    364 }
    365 
    366 const u_char *
    367 p_cdnname(const u_char *cp, const u_char *msg, int len, FILE *file) {
    368 	char name[MAXDNAME];
    369 	int n;
    370 
    371 	if ((n = dn_expand(msg, msg + len, cp, name, (int)sizeof name)) < 0)
    372 		return (NULL);
    373 	if (name[0] == '\0')
    374 		putc('.', file);
    375 	else
    376 		fputs(name, file);
    377 	return (cp + n);
    378 }
    379 
    380 const u_char *
    381 p_cdname(const u_char *cp, const u_char *msg, FILE *file) {
    382 	return (p_cdnname(cp, msg, PACKETSZ, file));
    383 }
    384 
    385 /*%
    386  * Return a fully-qualified domain name from a compressed name (with
    387    length supplied).  */
    388 
    389 const u_char *
    390 p_fqnname(const u_char *cp, const u_char *msg, int msglen, char *name,
    391     int namelen)
    392 {
    393 	int n;
    394 	size_t newlen;
    395 
    396 	if ((n = dn_expand(msg, cp + msglen, cp, name, namelen)) < 0)
    397 		return (NULL);
    398 	newlen = strlen(name);
    399 	if (newlen == 0 || name[newlen - 1] != '.') {
    400 		if ((int)newlen + 1 >= namelen)	/*%< Lack space for final dot */
    401 			return (NULL);
    402 		else
    403 			strcpy(name + newlen, ".");
    404 	}
    405 	return (cp + n);
    406 }
    407 
    408 /* XXX:	the rest of these functions need to become length-limited, too. */
    409 
    410 const u_char *
    411 p_fqname(const u_char *cp, const u_char *msg, FILE *file) {
    412 	char name[MAXDNAME];
    413 	const u_char *n;
    414 
    415 	n = p_fqnname(cp, msg, MAXCDNAME, name, (int)sizeof name);
    416 	if (n == NULL)
    417 		return (NULL);
    418 	fputs(name, file);
    419 	return (n);
    420 }
    421 
    422 /*%
    423  * Names of RR classes and qclasses.  Classes and qclasses are the same, except
    424  * that C_ANY is a qclass but not a class.  (You can ask for records of class
    425  * C_ANY, but you can't have any records of that class in the database.)
    426  */
    427 const struct res_sym __p_class_syms[] = {
    428 	{C_IN,		"IN",		(char *)0},
    429 	{C_CHAOS,	"CH",		(char *)0},
    430 	{C_CHAOS,	"CHAOS",	(char *)0},
    431 	{C_HS,		"HS",		(char *)0},
    432 	{C_HS,		"HESIOD",	(char *)0},
    433 	{C_ANY,		"ANY",		(char *)0},
    434 	{C_NONE,	"NONE",		(char *)0},
    435 	{C_IN, 		(char *)0,	(char *)0}
    436 };
    437 
    438 /*%
    439  * Names of message sections.
    440  */
    441 const struct res_sym __p_default_section_syms[] = {
    442 	{ns_s_qd,	"QUERY",	(char *)0},
    443 	{ns_s_an,	"ANSWER",	(char *)0},
    444 	{ns_s_ns,	"AUTHORITY",	(char *)0},
    445 	{ns_s_ar,	"ADDITIONAL",	(char *)0},
    446 	{0,		(char *)0,	(char *)0}
    447 };
    448 
    449 const struct res_sym __p_update_section_syms[] = {
    450 	{S_ZONE,	"ZONE",		(char *)0},
    451 	{S_PREREQ,	"PREREQUISITE",	(char *)0},
    452 	{S_UPDATE,	"UPDATE",	(char *)0},
    453 	{S_ADDT,	"ADDITIONAL",	(char *)0},
    454 	{0,		(char *)0,	(char *)0}
    455 };
    456 
    457 const struct res_sym __p_key_syms[] = {
    458 	{NS_ALG_MD5RSA,		"RSA",		"RSA KEY with MD5 hash"},
    459 	{NS_ALG_DH,		"DH",		"Diffie Hellman"},
    460 	{NS_ALG_DSA,		"DSA",		"Digital Signature Algorithm"},
    461 	{NS_ALG_EXPIRE_ONLY,	"EXPIREONLY",	"No algorithm"},
    462 	{NS_ALG_PRIVATE_OID,	"PRIVATE",	"Algorithm obtained from OID"},
    463 	{0,			NULL,		NULL}
    464 };
    465 
    466 const struct res_sym __p_cert_syms[] = {
    467 	{cert_t_pkix,	"PKIX",		"PKIX (X.509v3) Certificate"},
    468 	{cert_t_spki,	"SPKI",		"SPKI certificate"},
    469 	{cert_t_pgp,	"PGP",		"PGP certificate"},
    470 	{cert_t_url,	"URL",		"URL Private"},
    471 	{cert_t_oid,	"OID",		"OID Private"},
    472 	{0,		NULL,		NULL}
    473 };
    474 
    475 /*%
    476  * Names of RR types and qtypes.  Types and qtypes are the same, except
    477  * that T_ANY is a qtype but not a type.  (You can ask for records of type
    478  * T_ANY, but you can't have any records of that type in the database.)
    479  */
    480 const struct res_sym __p_type_syms[] = {
    481 	{ns_t_a,	"A",		"address"},
    482 	{ns_t_ns,	"NS",		"name server"},
    483 	{ns_t_md,	"MD",		"mail destination (deprecated)"},
    484 	{ns_t_mf,	"MF",		"mail forwarder (deprecated)"},
    485 	{ns_t_cname,	"CNAME",	"canonical name"},
    486 	{ns_t_soa,	"SOA",		"start of authority"},
    487 	{ns_t_mb,	"MB",		"mailbox"},
    488 	{ns_t_mg,	"MG",		"mail group member"},
    489 	{ns_t_mr,	"MR",		"mail rename"},
    490 	{ns_t_null,	"NULL",		"null"},
    491 	{ns_t_wks,	"WKS",		"well-known service (deprecated)"},
    492 	{ns_t_ptr,	"PTR",		"domain name pointer"},
    493 	{ns_t_hinfo,	"HINFO",	"host information"},
    494 	{ns_t_minfo,	"MINFO",	"mailbox information"},
    495 	{ns_t_mx,	"MX",		"mail exchanger"},
    496 	{ns_t_txt,	"TXT",		"text"},
    497 	{ns_t_rp,	"RP",		"responsible person"},
    498 	{ns_t_afsdb,	"AFSDB",	"DCE or AFS server"},
    499 	{ns_t_x25,	"X25",		"X25 address"},
    500 	{ns_t_isdn,	"ISDN",		"ISDN address"},
    501 	{ns_t_rt,	"RT",		"router"},
    502 	{ns_t_nsap,	"NSAP",		"nsap address"},
    503 	{ns_t_nsap_ptr,	"NSAP_PTR",	"domain name pointer"},
    504 	{ns_t_sig,	"SIG",		"signature"},
    505 	{ns_t_key,	"KEY",		"key"},
    506 	{ns_t_px,	"PX",		"mapping information"},
    507 	{ns_t_gpos,	"GPOS",		"geographical position (withdrawn)"},
    508 	{ns_t_aaaa,	"AAAA",		"IPv6 address"},
    509 	{ns_t_loc,	"LOC",		"location"},
    510 	{ns_t_nxt,	"NXT",		"next valid name (unimplemented)"},
    511 	{ns_t_eid,	"EID",		"endpoint identifier (unimplemented)"},
    512 	{ns_t_nimloc,	"NIMLOC",	"NIMROD locator (unimplemented)"},
    513 	{ns_t_srv,	"SRV",		"server selection"},
    514 	{ns_t_atma,	"ATMA",		"ATM address (unimplemented)"},
    515 	{ns_t_naptr,	"NAPTR",	"naptr"},
    516 	{ns_t_kx,	"KX",		"key exchange"},
    517 	{ns_t_cert,	"CERT",		"certificate"},
    518 	{ns_t_a6,	"A",		"IPv6 address (experminental)"},
    519 	{ns_t_dname,	"DNAME",	"non-terminal redirection"},
    520 	{ns_t_opt,	"OPT",		"opt"},
    521 	{ns_t_apl,	"apl",		"apl"},
    522 	{ns_t_ds,	"DS",		"delegation signer"},
    523 	{ns_t_sshfp,	"SSFP",		"SSH fingerprint"},
    524 	{ns_t_ipseckey,	"IPSECKEY",	"IPSEC key"},
    525 	{ns_t_rrsig,	"RRSIG",	"rrsig"},
    526 	{ns_t_nsec,	"NSEC",		"nsec"},
    527 	{ns_t_dnskey,	"DNSKEY",	"DNS key"},
    528 	{ns_t_dhcid,	"DHCID",       "dynamic host configuration identifier"},
    529 	{ns_t_nsec3,	"NSEC3",	"nsec3"},
    530 	{ns_t_nsec3param, "NSEC3PARAM", "NSEC3 parameters"},
    531 	{ns_t_hip,	"HIP",		"host identity protocol"},
    532 	{ns_t_spf,	"SPF",		"sender policy framework"},
    533 	{ns_t_tkey,	"TKEY",		"tkey"},
    534 	{ns_t_tsig,	"TSIG",		"transaction signature"},
    535 	{ns_t_ixfr,	"IXFR",		"incremental zone transfer"},
    536 	{ns_t_axfr,	"AXFR",		"zone transfer"},
    537 	{ns_t_zxfr,	"ZXFR",		"compressed zone transfer"},
    538 	{ns_t_mailb,	"MAILB",	"mailbox-related data (deprecated)"},
    539 	{ns_t_maila,	"MAILA",	"mail agent (deprecated)"},
    540 	{ns_t_naptr,	"NAPTR",	"URN Naming Authority"},
    541 	{ns_t_kx,	"KX",		"Key Exchange"},
    542 	{ns_t_cert,	"CERT",		"Certificate"},
    543 	{ns_t_a6,	"A6",		"IPv6 Address"},
    544 	{ns_t_dname,	"DNAME",	"dname"},
    545 	{ns_t_sink,	"SINK",		"Kitchen Sink (experimental)"},
    546 	{ns_t_opt,	"OPT",		"EDNS Options"},
    547 	{ns_t_any,	"ANY",		"\"any\""},
    548 	{ns_t_dlv,	"DLV",		"DNSSEC look-aside validation"},
    549 	{0, 		NULL,		NULL}
    550 };
    551 
    552 /*%
    553  * Names of DNS rcodes.
    554  */
    555 const struct res_sym __p_rcode_syms[] = {
    556 	{ns_r_noerror,	"NOERROR",		"no error"},
    557 	{ns_r_formerr,	"FORMERR",		"format error"},
    558 	{ns_r_servfail,	"SERVFAIL",		"server failed"},
    559 	{ns_r_nxdomain,	"NXDOMAIN",		"no such domain name"},
    560 	{ns_r_notimpl,	"NOTIMP",		"not implemented"},
    561 	{ns_r_refused,	"REFUSED",		"refused"},
    562 	{ns_r_yxdomain,	"YXDOMAIN",		"domain name exists"},
    563 	{ns_r_yxrrset,	"YXRRSET",		"rrset exists"},
    564 	{ns_r_nxrrset,	"NXRRSET",		"rrset doesn't exist"},
    565 	{ns_r_notauth,	"NOTAUTH",		"not authoritative"},
    566 	{ns_r_notzone,	"NOTZONE",		"Not in zone"},
    567 	{ns_r_max,	"",			""},
    568 	{ns_r_badsig,	"BADSIG",		"bad signature"},
    569 	{ns_r_badkey,	"BADKEY",		"bad key"},
    570 	{ns_r_badtime,	"BADTIME",		"bad time"},
    571 	{0, 		NULL,			NULL}
    572 };
    573 
    574 int
    575 sym_ston(const struct res_sym *syms, const char *name, int *success) {
    576 	for (; syms->name != 0; syms++) {
    577 		if (strcasecmp (name, syms->name) == 0) {
    578 			if (success)
    579 				*success = 1;
    580 			return (syms->number);
    581 		}
    582 	}
    583 	if (success)
    584 		*success = 0;
    585 	return (syms->number);		/*%< The default value. */
    586 }
    587 
    588 const char *
    589 sym_ntos(const struct res_sym *syms, int number, int *success) {
    590 	char *unname = sym_ntos_unname;
    591 
    592 	for (; syms->name != 0; syms++) {
    593 		if (number == syms->number) {
    594 			if (success)
    595 				*success = 1;
    596 			return (syms->name);
    597 		}
    598 	}
    599 
    600 	sprintf(unname, "%d", number);		/*%< XXX nonreentrant */
    601 	if (success)
    602 		*success = 0;
    603 	return (unname);
    604 }
    605 
    606 const char *
    607 sym_ntop(const struct res_sym *syms, int number, int *success) {
    608 	char *unname = sym_ntop_unname;
    609 
    610 	for (; syms->name != 0; syms++) {
    611 		if (number == syms->number) {
    612 			if (success)
    613 				*success = 1;
    614 			return (syms->humanname);
    615 		}
    616 	}
    617 	sprintf(unname, "%d", number);		/*%< XXX nonreentrant */
    618 	if (success)
    619 		*success = 0;
    620 	return (unname);
    621 }
    622 
    623 /*%
    624  * Return a string for the type.
    625  */
    626 const char *
    627 p_type(int type) {
    628 	int success;
    629 	const char *result;
    630 	static char typebuf[20];
    631 
    632 	result = sym_ntos(__p_type_syms, type, &success);
    633 	if (success)
    634 		return (result);
    635 	if (type < 0 || type > 0xffff)
    636 		return ("BADTYPE");
    637 	sprintf(typebuf, "TYPE%d", type);
    638 	return (typebuf);
    639 }
    640 
    641 /*%
    642  * Return a string for the type.
    643  */
    644 const char *
    645 p_section(int section, int opcode) {
    646 	const struct res_sym *symbols;
    647 
    648 	switch (opcode) {
    649 	case ns_o_update:
    650 		symbols = __p_update_section_syms;
    651 		break;
    652 	default:
    653 		symbols = __p_default_section_syms;
    654 		break;
    655 	}
    656 	return (sym_ntos(symbols, section, (int *)0));
    657 }
    658 
    659 /*%
    660  * Return a mnemonic for class.
    661  */
    662 const char *
    663 p_class(int class) {
    664 	int success;
    665 	const char *result;
    666 	static char classbuf[20];
    667 
    668 	result = sym_ntos(__p_class_syms, class, &success);
    669 	if (success)
    670 		return (result);
    671 	if (class < 0 || class > 0xffff)
    672 		return ("BADCLASS");
    673 	sprintf(classbuf, "CLASS%d", class);
    674 	return (classbuf);
    675 }
    676 
    677 /*%
    678  * Return a mnemonic for an option
    679  */
    680 const char *
    681 p_option(u_long option) {
    682 	char *nbuf = p_option_nbuf;
    683 
    684 	switch (option) {
    685 	case RES_INIT:		return "init";
    686 	case RES_DEBUG:		return "debug";
    687 	case RES_AAONLY:	return "aaonly(unimpl)";
    688 	case RES_USEVC:		return "usevc";
    689 	case RES_PRIMARY:	return "primry(unimpl)";
    690 	case RES_IGNTC:		return "igntc";
    691 	case RES_RECURSE:	return "recurs";
    692 	case RES_DEFNAMES:	return "defnam";
    693 	case RES_STAYOPEN:	return "styopn";
    694 	case RES_DNSRCH:	return "dnsrch";
    695 	case RES_INSECURE1:	return "insecure1";
    696 	case RES_INSECURE2:	return "insecure2";
    697 	case RES_NOALIASES:	return "noaliases";
    698 	case RES_USE_INET6:	return "inet6";
    699 #ifdef RES_USE_EDNS0	/*%< KAME extension */
    700 	case RES_USE_EDNS0:	return "edns0";
    701 	case RES_NSID:		return "nsid";
    702 #endif
    703 #ifdef RES_USE_DNAME
    704 	case RES_USE_DNAME:	return "dname";
    705 #endif
    706 #ifdef RES_USE_DNSSEC
    707 	case RES_USE_DNSSEC:	return "dnssec";
    708 #endif
    709 #ifdef RES_NOTLDQUERY
    710 	case RES_NOTLDQUERY:	return "no-tld-query";
    711 #endif
    712 #ifdef RES_NO_NIBBLE2
    713 	case RES_NO_NIBBLE2:	return "no-nibble2";
    714 #endif
    715 				/* XXX nonreentrant */
    716 	default:		sprintf(nbuf, "?0x%lx?", (u_long)option);
    717 				return (nbuf);
    718 	}
    719 }
    720 
    721 /*%
    722  * Return a mnemonic for a time to live.
    723  */
    724 const char *
    725 p_time(u_int32_t value) {
    726 	char *nbuf = p_time_nbuf;
    727 
    728 	if (ns_format_ttl((u_long)value, nbuf, sizeof nbuf) < 0)
    729 		sprintf(nbuf, "%u", value);
    730 	return (nbuf);
    731 }
    732 
    733 /*%
    734  * Return a string for the rcode.
    735  */
    736 const char *
    737 p_rcode(int rcode) {
    738 	return (sym_ntos(__p_rcode_syms, rcode, (int *)0));
    739 }
    740 
    741 /*%
    742  * Return a string for a res_sockaddr_union.
    743  */
    744 const char *
    745 p_sockun(union res_sockaddr_union u, char *buf, size_t size) {
    746 	char ret[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:123.123.123.123"];
    747 
    748 	switch (u.sin.sin_family) {
    749 	case AF_INET:
    750 		inet_ntop(AF_INET, &u.sin.sin_addr, ret, (socklen_t)sizeof ret);
    751 		break;
    752 #ifdef HAS_INET6_STRUCTS
    753 	case AF_INET6:
    754 		inet_ntop(AF_INET6, &u.sin6.sin6_addr, ret, sizeof ret);
    755 		break;
    756 #endif
    757 	default:
    758 		sprintf(ret, "[af%d]", u.sin.sin_family);
    759 		break;
    760 	}
    761 	if (size > 0U) {
    762 		strncpy(buf, ret, size - 1);
    763 		buf[size - 1] = '0';
    764 	}
    765 	return (buf);
    766 }
    767 
    768 /*%
    769  * routines to convert between on-the-wire RR format and zone file format.
    770  * Does not contain conversion to/from decimal degrees; divide or multiply
    771  * by 60*60*1000 for that.
    772  */
    773 
    774 static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
    775 				      1000000,10000000,100000000,1000000000};
    776 
    777 /*% takes an XeY precision/size value, returns a string representation. */
    778 static const char *
    779 precsize_ntoa(u_int32_t prec)
    780 {
    781 	char *retbuf = precsize_ntoa_retbuf;
    782 	unsigned long val;
    783 	int mantissa, exponent;
    784 
    785 	mantissa = (int)((prec >> 4) & 0x0f) % 10;
    786 	exponent = (int)((prec >> 0) & 0x0f) % 10;
    787 
    788 	val = mantissa * poweroften[exponent];
    789 
    790 	(void) sprintf(retbuf, "%lu.%.2lu", val/100, val%100);
    791 	return (retbuf);
    792 }
    793 
    794 /*% converts ascii size/precision X * 10**Y(cm) to 0xXY.  moves pointer.  */
    795 static u_int8_t
    796 precsize_aton(const char **strptr) {
    797 	unsigned int mval = 0, cmval = 0;
    798 	u_int8_t retval = 0;
    799 	const char *cp;
    800 	int exponent;
    801 	int mantissa;
    802 
    803 	cp = *strptr;
    804 
    805 	while (isdigit((unsigned char)*cp))
    806 		mval = mval * 10 + (*cp++ - '0');
    807 
    808 	if (*cp == '.') {		/*%< centimeters */
    809 		cp++;
    810 		if (isdigit((unsigned char)*cp)) {
    811 			cmval = (*cp++ - '0') * 10;
    812 			if (isdigit((unsigned char)*cp)) {
    813 				cmval += (*cp++ - '0');
    814 			}
    815 		}
    816 	}
    817 	cmval = (mval * 100) + cmval;
    818 
    819 	for (exponent = 0; exponent < 9; exponent++)
    820 		if (cmval < poweroften[exponent+1])
    821 			break;
    822 
    823 	mantissa = cmval / poweroften[exponent];
    824 	if (mantissa > 9)
    825 		mantissa = 9;
    826 
    827 	retval = (mantissa << 4) | exponent;
    828 
    829 	*strptr = cp;
    830 
    831 	return (retval);
    832 }
    833 
    834 /*% converts ascii lat/lon to unsigned encoded 32-bit number.  moves pointer. */
    835 static u_int32_t
    836 latlon2ul(const char **latlonstrptr, int *which) {
    837 	const char *cp;
    838 	u_int32_t retval;
    839 	int deg = 0, min = 0, secs = 0, secsfrac = 0;
    840 
    841 	cp = *latlonstrptr;
    842 
    843 	while (isdigit((unsigned char)*cp))
    844 		deg = deg * 10 + (*cp++ - '0');
    845 
    846 	while (isspace((unsigned char)*cp))
    847 		cp++;
    848 
    849 	if (!(isdigit((unsigned char)*cp)))
    850 		goto fndhemi;
    851 
    852 	while (isdigit((unsigned char)*cp))
    853 		min = min * 10 + (*cp++ - '0');
    854 
    855 	while (isspace((unsigned char)*cp))
    856 		cp++;
    857 
    858 	if (!(isdigit((unsigned char)*cp)))
    859 		goto fndhemi;
    860 
    861 	while (isdigit((unsigned char)*cp))
    862 		secs = secs * 10 + (*cp++ - '0');
    863 
    864 	if (*cp == '.') {		/*%< decimal seconds */
    865 		cp++;
    866 		if (isdigit((unsigned char)*cp)) {
    867 			secsfrac = (*cp++ - '0') * 100;
    868 			if (isdigit((unsigned char)*cp)) {
    869 				secsfrac += (*cp++ - '0') * 10;
    870 				if (isdigit((unsigned char)*cp)) {
    871 					secsfrac += (*cp++ - '0');
    872 				}
    873 			}
    874 		}
    875 	}
    876 
    877 	while (!isspace((unsigned char)*cp))	/*%< if any trailing garbage */
    878 		cp++;
    879 
    880 	while (isspace((unsigned char)*cp))
    881 		cp++;
    882 
    883  fndhemi:
    884 	switch (*cp) {
    885 	case 'N': case 'n':
    886 	case 'E': case 'e':
    887 		retval = ((unsigned)1<<31)
    888 			+ (((((deg * 60) + min) * 60) + secs) * 1000)
    889 			+ secsfrac;
    890 		break;
    891 	case 'S': case 's':
    892 	case 'W': case 'w':
    893 		retval = ((unsigned)1<<31)
    894 			- (((((deg * 60) + min) * 60) + secs) * 1000)
    895 			- secsfrac;
    896 		break;
    897 	default:
    898 		retval = 0;	/*%< invalid value -- indicates error */
    899 		break;
    900 	}
    901 
    902 	switch (*cp) {
    903 	case 'N': case 'n':
    904 	case 'S': case 's':
    905 		*which = 1;	/*%< latitude */
    906 		break;
    907 	case 'E': case 'e':
    908 	case 'W': case 'w':
    909 		*which = 2;	/*%< longitude */
    910 		break;
    911 	default:
    912 		*which = 0;	/*%< error */
    913 		break;
    914 	}
    915 
    916 	cp++;			/*%< skip the hemisphere */
    917 	while (!isspace((unsigned char)*cp))	/*%< if any trailing garbage */
    918 		cp++;
    919 
    920 	while (isspace((unsigned char)*cp))	/*%< move to next field */
    921 		cp++;
    922 
    923 	*latlonstrptr = cp;
    924 
    925 	return (retval);
    926 }
    927 
    928 /*%
    929  * converts a zone file representation in a string to an RDATA on-the-wire
    930  * representation. */
    931 int
    932 loc_aton(const char *ascii, u_char *binary)
    933 {
    934 	const char *cp, *maxcp;
    935 	u_char *bcp;
    936 
    937 	u_int32_t latit = 0, longit = 0, alt = 0;
    938 	u_int32_t lltemp1 = 0, lltemp2 = 0;
    939 	int altmeters = 0, altfrac = 0, altsign = 1;
    940 	u_int8_t hp = 0x16;	/*%< default = 1e6 cm = 10000.00m = 10km */
    941 	u_int8_t vp = 0x13;	/*%< default = 1e3 cm = 10.00m */
    942 	u_int8_t siz = 0x12;	/*%< default = 1e2 cm = 1.00m */
    943 	int which1 = 0, which2 = 0;
    944 
    945 	cp = ascii;
    946 	maxcp = cp + strlen(ascii);
    947 
    948 	lltemp1 = latlon2ul(&cp, &which1);
    949 
    950 	lltemp2 = latlon2ul(&cp, &which2);
    951 
    952 	switch (which1 + which2) {
    953 	case 3:			/*%< 1 + 2, the only valid combination */
    954 		if ((which1 == 1) && (which2 == 2)) { /*%< normal case */
    955 			latit = lltemp1;
    956 			longit = lltemp2;
    957 		} else if ((which1 == 2) && (which2 == 1)) { /*%< reversed */
    958 			longit = lltemp1;
    959 			latit = lltemp2;
    960 		} else {	/*%< some kind of brokenness */
    961 			return (0);
    962 		}
    963 		break;
    964 	default:		/*%< we didn't get one of each */
    965 		return (0);
    966 	}
    967 
    968 	/* altitude */
    969 	if (*cp == '-') {
    970 		altsign = -1;
    971 		cp++;
    972 	}
    973 
    974 	if (*cp == '+')
    975 		cp++;
    976 
    977 	while (isdigit((unsigned char)*cp))
    978 		altmeters = altmeters * 10 + (*cp++ - '0');
    979 
    980 	if (*cp == '.') {		/*%< decimal meters */
    981 		cp++;
    982 		if (isdigit((unsigned char)*cp)) {
    983 			altfrac = (*cp++ - '0') * 10;
    984 			if (isdigit((unsigned char)*cp)) {
    985 				altfrac += (*cp++ - '0');
    986 			}
    987 		}
    988 	}
    989 
    990 	alt = (10000000 + (altsign * (altmeters * 100 + altfrac)));
    991 
    992 	while (!isspace((unsigned char)*cp) && (cp < maxcp)) /*%< if trailing garbage or m */
    993 		cp++;
    994 
    995 	while (isspace((unsigned char)*cp) && (cp < maxcp))
    996 		cp++;
    997 
    998 	if (cp >= maxcp)
    999 		goto defaults;
   1000 
   1001 	siz = precsize_aton(&cp);
   1002 
   1003 	while (!isspace((unsigned char)*cp) && (cp < maxcp))	/*%< if trailing garbage or m */
   1004 		cp++;
   1005 
   1006 	while (isspace((unsigned char)*cp) && (cp < maxcp))
   1007 		cp++;
   1008 
   1009 	if (cp >= maxcp)
   1010 		goto defaults;
   1011 
   1012 	hp = precsize_aton(&cp);
   1013 
   1014 	while (!isspace((unsigned char)*cp) && (cp < maxcp))	/*%< if trailing garbage or m */
   1015 		cp++;
   1016 
   1017 	while (isspace((unsigned char)*cp) && (cp < maxcp))
   1018 		cp++;
   1019 
   1020 	if (cp >= maxcp)
   1021 		goto defaults;
   1022 
   1023 	vp = precsize_aton(&cp);
   1024 
   1025  defaults:
   1026 
   1027 	bcp = binary;
   1028 	*bcp++ = (u_int8_t) 0;	/*%< version byte */
   1029 	*bcp++ = siz;
   1030 	*bcp++ = hp;
   1031 	*bcp++ = vp;
   1032 	PUTLONG(latit,bcp);
   1033 	PUTLONG(longit,bcp);
   1034 	PUTLONG(alt,bcp);
   1035 
   1036 	return (16);		/*%< size of RR in octets */
   1037 }
   1038 
   1039 /*% takes an on-the-wire LOC RR and formats it in a human readable format. */
   1040 const char *
   1041 loc_ntoa(const u_char *binary, char *ascii)
   1042 {
   1043 	static const char *error = "?";
   1044 	static char tmpbuf[sizeof
   1045 "1000 60 60.000 N 1000 60 60.000 W -12345678.00m 90000000.00m 90000000.00m 90000000.00m"];
   1046 	const u_char *cp = binary;
   1047 
   1048 	int latdeg, latmin, latsec, latsecfrac;
   1049 	int longdeg, longmin, longsec, longsecfrac;
   1050 	char northsouth, eastwest;
   1051 	const char *altsign;
   1052 	int altmeters, altfrac;
   1053 
   1054 	const u_int32_t referencealt = 100000 * 100;
   1055 
   1056 	int32_t latval, longval, altval;
   1057 	u_int32_t templ;
   1058 	u_int8_t sizeval, hpval, vpval, versionval;
   1059 
   1060 	char *sizestr, *hpstr, *vpstr;
   1061 
   1062 	versionval = *cp++;
   1063 
   1064 	if (ascii == NULL)
   1065 		ascii = tmpbuf;
   1066 
   1067 	if (versionval) {
   1068 		(void) sprintf(ascii, "; error: unknown LOC RR version");
   1069 		return (ascii);
   1070 	}
   1071 
   1072 	sizeval = *cp++;
   1073 
   1074 	hpval = *cp++;
   1075 	vpval = *cp++;
   1076 
   1077 	GETLONG(templ, cp);
   1078 	latval = (templ - ((unsigned)1<<31));
   1079 
   1080 	GETLONG(templ, cp);
   1081 	longval = (templ - ((unsigned)1<<31));
   1082 
   1083 	GETLONG(templ, cp);
   1084 	if (templ < referencealt) { /*%< below WGS 84 spheroid */
   1085 		altval = referencealt - templ;
   1086 		altsign = "-";
   1087 	} else {
   1088 		altval = templ - referencealt;
   1089 		altsign = "";
   1090 	}
   1091 
   1092 	if (latval < 0) {
   1093 		northsouth = 'S';
   1094 		latval = -latval;
   1095 	} else
   1096 		northsouth = 'N';
   1097 
   1098 	latsecfrac = latval % 1000;
   1099 	latval = latval / 1000;
   1100 	latsec = latval % 60;
   1101 	latval = latval / 60;
   1102 	latmin = latval % 60;
   1103 	latval = latval / 60;
   1104 	latdeg = latval;
   1105 
   1106 	if (longval < 0) {
   1107 		eastwest = 'W';
   1108 		longval = -longval;
   1109 	} else
   1110 		eastwest = 'E';
   1111 
   1112 	longsecfrac = longval % 1000;
   1113 	longval = longval / 1000;
   1114 	longsec = longval % 60;
   1115 	longval = longval / 60;
   1116 	longmin = longval % 60;
   1117 	longval = longval / 60;
   1118 	longdeg = longval;
   1119 
   1120 	altfrac = altval % 100;
   1121 	altmeters = (altval / 100);
   1122 
   1123 	sizestr = strdup(precsize_ntoa((u_int32_t)sizeval));
   1124 	hpstr = strdup(precsize_ntoa((u_int32_t)hpval));
   1125 	vpstr = strdup(precsize_ntoa((u_int32_t)vpval));
   1126 
   1127 	sprintf(ascii,
   1128 	    "%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %s%d.%.2dm %sm %sm %sm",
   1129 		latdeg, latmin, latsec, latsecfrac, northsouth,
   1130 		longdeg, longmin, longsec, longsecfrac, eastwest,
   1131 		altsign, altmeters, altfrac,
   1132 		(sizestr != NULL) ? sizestr : error,
   1133 		(hpstr != NULL) ? hpstr : error,
   1134 		(vpstr != NULL) ? vpstr : error);
   1135 
   1136 	if (sizestr != NULL)
   1137 		free(sizestr);
   1138 	if (hpstr != NULL)
   1139 		free(hpstr);
   1140 	if (vpstr != NULL)
   1141 		free(vpstr);
   1142 
   1143 	return (ascii);
   1144 }
   1145 
   1146 
   1147 /*% Return the number of DNS hierarchy levels in the name. */
   1148 int
   1149 dn_count_labels(const char *name) {
   1150 	size_t len, i, count;
   1151 
   1152 	len = strlen(name);
   1153 	for (i = 0, count = 0; i < len; i++) {
   1154 		/* XXX need to check for \. or use named's nlabels(). */
   1155 		if (name[i] == '.')
   1156 			count++;
   1157 	}
   1158 
   1159 	/* don't count initial wildcard */
   1160 	if (name[0] == '*')
   1161 		if (count)
   1162 			count--;
   1163 
   1164 	/* don't count the null label for root. */
   1165 	/* if terminating '.' not found, must adjust */
   1166 	/* count to include last label */
   1167 	if (len > 0 && name[len-1] != '.')
   1168 		count++;
   1169 	_DIAGASSERT(__type_fit(int, count));
   1170 	return (int)count;
   1171 }
   1172 
   1173 /*%
   1174  * Make dates expressed in seconds-since-Jan-1-1970 easy to read.
   1175  * SIG records are required to be printed like this, by the Secure DNS RFC.
   1176  */
   1177 char *
   1178 p_secstodate (u_long secs) {
   1179 	/* XXX nonreentrant */
   1180 	char *output = p_secstodate_output;
   1181 	time_t myclock = secs;
   1182 	struct tm *mytime;
   1183 #ifdef HAVE_TIME_R
   1184 	struct tm res;
   1185 
   1186 	mytime = gmtime_r(&myclock, &res);
   1187 #else
   1188 	mytime = gmtime(&myclock);
   1189 #endif
   1190 	mytime->tm_year += 1900;
   1191 	mytime->tm_mon += 1;
   1192 	sprintf(output, "%04d%02d%02d%02d%02d%02d",
   1193 		mytime->tm_year, mytime->tm_mon, mytime->tm_mday,
   1194 		mytime->tm_hour, mytime->tm_min, mytime->tm_sec);
   1195 	return (output);
   1196 }
   1197 
   1198 u_int16_t
   1199 res_nametoclass(const char *buf, int *successp) {
   1200 	unsigned long result;
   1201 	char *endptr;
   1202 	int success;
   1203 
   1204 	result = sym_ston(__p_class_syms, buf, &success);
   1205 	if (success)
   1206 		goto done;
   1207 
   1208 	if (strncasecmp(buf, "CLASS", 5) != 0 ||
   1209 	    !isdigit((unsigned char)buf[5]))
   1210 		goto done;
   1211 	errno = 0;
   1212 	result = strtoul(buf + 5, &endptr, 10);
   1213 	if (errno == 0 && *endptr == '\0' && result <= 0xffffU)
   1214 		success = 1;
   1215  done:
   1216 	if (successp)
   1217 		*successp = success;
   1218 	return (u_int16_t)(result);
   1219 }
   1220 
   1221 u_int16_t
   1222 res_nametotype(const char *buf, int *successp) {
   1223 	unsigned long result;
   1224 	char *endptr;
   1225 	int success;
   1226 
   1227 	result = sym_ston(__p_type_syms, buf, &success);
   1228 	if (success)
   1229 		goto done;
   1230 
   1231 	if (strncasecmp(buf, "type", 4) != 0 ||
   1232 	    !isdigit((unsigned char)buf[4]))
   1233 		goto done;
   1234 	errno = 0;
   1235 	result = strtoul(buf + 4, &endptr, 10);
   1236 	if (errno == 0 && *endptr == '\0' && result <= 0xffffU)
   1237 		success = 1;
   1238  done:
   1239 	if (successp)
   1240 		*successp = success;
   1241 	return (u_int16_t)(result);
   1242 }
   1243 
   1244 /*! \file */
   1245