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