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