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