1/*	$NetBSD$	*/
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#if defined(LIBC_SCCS) && !defined(lint)
99static const char sccsid[] = "@(#)res_debug.c	8.1 (Berkeley) 6/4/93";
100static const char rcsid[] = "Id: res_debug.c,v 1.19 2009/02/26 11:20:20 tbox Exp ";
101#endif /* LIBC_SCCS and not lint */
102
103#include "port_before.h"
104
105#include <sys/types.h>
106#include <sys/param.h>
107#include <sys/socket.h>
108
109#include <netinet/in.h>
110#include <arpa/inet.h>
111#include <arpa/nameser.h>
112
113#include <ctype.h>
114#include <errno.h>
115#include <math.h>
116#include <netdb.h>
117#include <resolv.h>
118#include <resolv_mt.h>
119#include <stdio.h>
120#include <stdlib.h>
121#include <string.h>
122#include <time.h>
123
124#include "port_after.h"
125
126#ifdef SPRINTF_CHAR
127# define SPRINTF(x) strlen(sprintf/**/x)
128#else
129# define SPRINTF(x) sprintf x
130#endif
131
132extern const char *_res_opcodes[];
133extern const char *_res_sectioncodes[];
134
135/*%
136 * Print the current options.
137 */
138void
139fp_resstat(const res_state statp, FILE *file) {
140	u_long mask;
141
142	fprintf(file, ";; res options:");
143	for (mask = 1;  mask != 0U;  mask <<= 1)
144		if (statp->options & mask)
145			fprintf(file, " %s", p_option(mask));
146	putc('\n', file);
147}
148
149static void
150do_section(const res_state statp,
151	   ns_msg *handle, ns_sect section,
152	   int pflag, FILE *file)
153{
154	int n, sflag, rrnum;
155	static int buflen = 2048;
156	char *buf;
157	ns_opcode opcode;
158	ns_rr rr;
159
160	/*
161	 * Print answer records.
162	 */
163	sflag = (statp->pfcode & pflag);
164	if (statp->pfcode && !sflag)
165		return;
166
167	buf = malloc(buflen);
168	if (buf == NULL) {
169		fprintf(file, ";; memory allocation failure\n");
170		return;
171	}
172
173	opcode = (ns_opcode) ns_msg_getflag(*handle, ns_f_opcode);
174	rrnum = 0;
175	for (;;) {
176		if (ns_parserr(handle, section, rrnum, &rr)) {
177			if (errno != ENODEV)
178				fprintf(file, ";; ns_parserr: %s\n",
179					strerror(errno));
180			else if (rrnum > 0 && sflag != 0 &&
181				 (statp->pfcode & RES_PRF_HEAD1))
182				putc('\n', file);
183			goto cleanup;
184		}
185		if (rrnum == 0 && sflag != 0 && (statp->pfcode & RES_PRF_HEAD1))
186			fprintf(file, ";; %s SECTION:\n",
187				p_section(section, opcode));
188		if (section == ns_s_qd)
189			fprintf(file, ";;\t%s, type = %s, class = %s\n",
190				ns_rr_name(rr),
191				p_type(ns_rr_type(rr)),
192				p_class(ns_rr_class(rr)));
193		else if (section == ns_s_ar && ns_rr_type(rr) == ns_t_opt) {
194			u_int16_t optcode, optlen, rdatalen = ns_rr_rdlen(rr);
195			u_int32_t ttl = ns_rr_ttl(rr);
196
197			fprintf(file,
198				"; EDNS: version: %u, udp=%u, flags=%04x\n",
199				(ttl>>16)&0xff, ns_rr_class(rr), ttl&0xffff);
200
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, buflen);
247			if (n < 0) {
248				if (errno == ENOSPC) {
249					free(buf);
250					buf = NULL;
251					if (buflen < 131072)
252						buf = malloc(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(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, opcode), qdcount);
327		fprintf(file, ", %s: %d",
328			p_section(ns_s_an, opcode), ancount);
329		fprintf(file, ", %s: %d",
330			p_section(ns_s_ns, opcode), nscount);
331		fprintf(file, ", %s: %d",
332			p_section(ns_s_ar, 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, 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/*%
370 * Return a fully-qualified domain name from a compressed name (with
371   length supplied).  */
372
373const u_char *
374p_fqnname(cp, msg, msglen, name, namelen)
375	const u_char *cp, *msg;
376	int msglen;
377	char *name;
378	int namelen;
379{
380	int n, newlen;
381
382	if ((n = dn_expand(msg, cp + msglen, cp, name, namelen)) < 0)
383		return (NULL);
384	newlen = strlen(name);
385	if (newlen == 0 || name[newlen - 1] != '.') {
386		if (newlen + 1 >= namelen)	/*%< Lack space for final dot */
387			return (NULL);
388		else
389			strcpy(name + newlen, ".");
390	}
391	return (cp + n);
392}
393
394/* XXX:	the rest of these functions need to become length-limited, too. */
395
396const u_char *
397p_fqname(const u_char *cp, const u_char *msg, FILE *file) {
398	char name[MAXDNAME];
399	const u_char *n;
400
401	n = p_fqnname(cp, msg, MAXCDNAME, name, sizeof name);
402	if (n == NULL)
403		return (NULL);
404	fputs(name, file);
405	return (n);
406}
407
408/*%
409 * Names of RR classes and qclasses.  Classes and qclasses are the same, except
410 * that C_ANY is a qclass but not a class.  (You can ask for records of class
411 * C_ANY, but you can't have any records of that class in the database.)
412 */
413const struct res_sym __p_class_syms[] = {
414	{C_IN,		"IN",		(char *)0},
415	{C_CHAOS,	"CH",		(char *)0},
416	{C_CHAOS,	"CHAOS",	(char *)0},
417	{C_HS,		"HS",		(char *)0},
418	{C_HS,		"HESIOD",	(char *)0},
419	{C_ANY,		"ANY",		(char *)0},
420	{C_NONE,	"NONE",		(char *)0},
421	{C_IN, 		(char *)0,	(char *)0}
422};
423
424/*%
425 * Names of message sections.
426 */
427const struct res_sym __p_default_section_syms[] = {
428	{ns_s_qd,	"QUERY",	(char *)0},
429	{ns_s_an,	"ANSWER",	(char *)0},
430	{ns_s_ns,	"AUTHORITY",	(char *)0},
431	{ns_s_ar,	"ADDITIONAL",	(char *)0},
432	{0,		(char *)0,	(char *)0}
433};
434
435const struct res_sym __p_update_section_syms[] = {
436	{S_ZONE,	"ZONE",		(char *)0},
437	{S_PREREQ,	"PREREQUISITE",	(char *)0},
438	{S_UPDATE,	"UPDATE",	(char *)0},
439	{S_ADDT,	"ADDITIONAL",	(char *)0},
440	{0,		(char *)0,	(char *)0}
441};
442
443const struct res_sym __p_key_syms[] = {
444	{NS_ALG_MD5RSA,		"RSA",		"RSA KEY with MD5 hash"},
445	{NS_ALG_DH,		"DH",		"Diffie Hellman"},
446	{NS_ALG_DSA,		"DSA",		"Digital Signature Algorithm"},
447	{NS_ALG_EXPIRE_ONLY,	"EXPIREONLY",	"No algorithm"},
448	{NS_ALG_PRIVATE_OID,	"PRIVATE",	"Algorithm obtained from OID"},
449	{0,			NULL,		NULL}
450};
451
452const struct res_sym __p_cert_syms[] = {
453	{cert_t_pkix,	"PKIX",		"PKIX (X.509v3) Certificate"},
454	{cert_t_spki,	"SPKI",		"SPKI certificate"},
455	{cert_t_pgp,	"PGP",		"PGP certificate"},
456	{cert_t_url,	"URL",		"URL Private"},
457	{cert_t_oid,	"OID",		"OID Private"},
458	{0,		NULL,		NULL}
459};
460
461/*%
462 * Names of RR types and qtypes.  Types and qtypes are the same, except
463 * that T_ANY is a qtype but not a type.  (You can ask for records of type
464 * T_ANY, but you can't have any records of that type in the database.)
465 */
466const struct res_sym __p_type_syms[] = {
467	{ns_t_a,	"A",		"address"},
468	{ns_t_ns,	"NS",		"name server"},
469	{ns_t_md,	"MD",		"mail destination (deprecated)"},
470	{ns_t_mf,	"MF",		"mail forwarder (deprecated)"},
471	{ns_t_cname,	"CNAME",	"canonical name"},
472	{ns_t_soa,	"SOA",		"start of authority"},
473	{ns_t_mb,	"MB",		"mailbox"},
474	{ns_t_mg,	"MG",		"mail group member"},
475	{ns_t_mr,	"MR",		"mail rename"},
476	{ns_t_null,	"NULL",		"null"},
477	{ns_t_wks,	"WKS",		"well-known service (deprecated)"},
478	{ns_t_ptr,	"PTR",		"domain name pointer"},
479	{ns_t_hinfo,	"HINFO",	"host information"},
480	{ns_t_minfo,	"MINFO",	"mailbox information"},
481	{ns_t_mx,	"MX",		"mail exchanger"},
482	{ns_t_txt,	"TXT",		"text"},
483	{ns_t_rp,	"RP",		"responsible person"},
484	{ns_t_afsdb,	"AFSDB",	"DCE or AFS server"},
485	{ns_t_x25,	"X25",		"X25 address"},
486	{ns_t_isdn,	"ISDN",		"ISDN address"},
487	{ns_t_rt,	"RT",		"router"},
488	{ns_t_nsap,	"NSAP",		"nsap address"},
489	{ns_t_nsap_ptr,	"NSAP_PTR",	"domain name pointer"},
490	{ns_t_sig,	"SIG",		"signature"},
491	{ns_t_key,	"KEY",		"key"},
492	{ns_t_px,	"PX",		"mapping information"},
493	{ns_t_gpos,	"GPOS",		"geographical position (withdrawn)"},
494	{ns_t_aaaa,	"AAAA",		"IPv6 address"},
495	{ns_t_loc,	"LOC",		"location"},
496	{ns_t_nxt,	"NXT",		"next valid name (unimplemented)"},
497	{ns_t_eid,	"EID",		"endpoint identifier (unimplemented)"},
498	{ns_t_nimloc,	"NIMLOC",	"NIMROD locator (unimplemented)"},
499	{ns_t_srv,	"SRV",		"server selection"},
500	{ns_t_atma,	"ATMA",		"ATM address (unimplemented)"},
501	{ns_t_naptr,	"NAPTR",	"naptr"},
502	{ns_t_kx,	"KX",		"key exchange"},
503	{ns_t_cert,	"CERT",		"certificate"},
504	{ns_t_a6,	"A",		"IPv6 address (experminental)"},
505	{ns_t_dname,	"DNAME",	"non-terminal redirection"},
506	{ns_t_opt,	"OPT",		"opt"},
507	{ns_t_apl,	"apl",		"apl"},
508	{ns_t_ds,	"DS",		"delegation signer"},
509	{ns_t_sshfp,	"SSFP",		"SSH fingerprint"},
510	{ns_t_ipseckey,	"IPSECKEY",	"IPSEC key"},
511	{ns_t_rrsig,	"RRSIG",	"rrsig"},
512	{ns_t_nsec,	"NSEC",		"nsec"},
513	{ns_t_dnskey,	"DNSKEY",	"DNS key"},
514	{ns_t_dhcid,	"DHCID",       "dynamic host configuration identifier"},
515	{ns_t_nsec3,	"NSEC3",	"nsec3"},
516	{ns_t_nsec3param, "NSEC3PARAM", "NSEC3 parameters"},
517	{ns_t_hip,	"HIP",		"host identity protocol"},
518	{ns_t_spf,	"SPF",		"sender policy framework"},
519	{ns_t_tkey,	"TKEY",		"tkey"},
520	{ns_t_tsig,	"TSIG",		"transaction signature"},
521	{ns_t_ixfr,	"IXFR",		"incremental zone transfer"},
522	{ns_t_axfr,	"AXFR",		"zone transfer"},
523	{ns_t_zxfr,	"ZXFR",		"compressed zone transfer"},
524	{ns_t_mailb,	"MAILB",	"mailbox-related data (deprecated)"},
525	{ns_t_maila,	"MAILA",	"mail agent (deprecated)"},
526	{ns_t_naptr,	"NAPTR",	"URN Naming Authority"},
527	{ns_t_kx,	"KX",		"Key Exchange"},
528	{ns_t_cert,	"CERT",		"Certificate"},
529	{ns_t_a6,	"A6",		"IPv6 Address"},
530	{ns_t_dname,	"DNAME",	"dname"},
531	{ns_t_sink,	"SINK",		"Kitchen Sink (experimental)"},
532	{ns_t_opt,	"OPT",		"EDNS Options"},
533	{ns_t_any,	"ANY",		"\"any\""},
534	{ns_t_dlv,	"DLV",		"DNSSEC look-aside validation"},
535	{0, 		NULL,		NULL}
536};
537
538/*%
539 * Names of DNS rcodes.
540 */
541const struct res_sym __p_rcode_syms[] = {
542	{ns_r_noerror,	"NOERROR",		"no error"},
543	{ns_r_formerr,	"FORMERR",		"format error"},
544	{ns_r_servfail,	"SERVFAIL",		"server failed"},
545	{ns_r_nxdomain,	"NXDOMAIN",		"no such domain name"},
546	{ns_r_notimpl,	"NOTIMP",		"not implemented"},
547	{ns_r_refused,	"REFUSED",		"refused"},
548	{ns_r_yxdomain,	"YXDOMAIN",		"domain name exists"},
549	{ns_r_yxrrset,	"YXRRSET",		"rrset exists"},
550	{ns_r_nxrrset,	"NXRRSET",		"rrset doesn't exist"},
551	{ns_r_notauth,	"NOTAUTH",		"not authoritative"},
552	{ns_r_notzone,	"NOTZONE",		"Not in zone"},
553	{ns_r_max,	"",			""},
554	{ns_r_badsig,	"BADSIG",		"bad signature"},
555	{ns_r_badkey,	"BADKEY",		"bad key"},
556	{ns_r_badtime,	"BADTIME",		"bad time"},
557	{0, 		NULL,			NULL}
558};
559
560int
561sym_ston(const struct res_sym *syms, const char *name, int *success) {
562	for ((void)NULL; syms->name != 0; syms++) {
563		if (strcasecmp (name, syms->name) == 0) {
564			if (success)
565				*success = 1;
566			return (syms->number);
567		}
568	}
569	if (success)
570		*success = 0;
571	return (syms->number);		/*%< The default value. */
572}
573
574const char *
575sym_ntos(const struct res_sym *syms, int number, int *success) {
576	char *unname = sym_ntos_unname;
577
578	for ((void)NULL; syms->name != 0; syms++) {
579		if (number == syms->number) {
580			if (success)
581				*success = 1;
582			return (syms->name);
583		}
584	}
585
586	sprintf(unname, "%d", number);		/*%< XXX nonreentrant */
587	if (success)
588		*success = 0;
589	return (unname);
590}
591
592const char *
593sym_ntop(const struct res_sym *syms, int number, int *success) {
594	char *unname = sym_ntop_unname;
595
596	for ((void)NULL; syms->name != 0; syms++) {
597		if (number == syms->number) {
598			if (success)
599				*success = 1;
600			return (syms->humanname);
601		}
602	}
603	sprintf(unname, "%d", number);		/*%< XXX nonreentrant */
604	if (success)
605		*success = 0;
606	return (unname);
607}
608
609/*%
610 * Return a string for the type.
611 */
612const char *
613p_type(int type) {
614	int success;
615	const char *result;
616	static char typebuf[20];
617
618	result = sym_ntos(__p_type_syms, type, &success);
619	if (success)
620		return (result);
621	if (type < 0 || type > 0xffff)
622		return ("BADTYPE");
623	sprintf(typebuf, "TYPE%d", type);
624	return (typebuf);
625}
626
627/*%
628 * Return a string for the type.
629 */
630const char *
631p_section(int section, int opcode) {
632	const struct res_sym *symbols;
633
634	switch (opcode) {
635	case ns_o_update:
636		symbols = __p_update_section_syms;
637		break;
638	default:
639		symbols = __p_default_section_syms;
640		break;
641	}
642	return (sym_ntos(symbols, section, (int *)0));
643}
644
645/*%
646 * Return a mnemonic for class.
647 */
648const char *
649p_class(int class) {
650	int success;
651	const char *result;
652	static char classbuf[20];
653
654	result = sym_ntos(__p_class_syms, class, &success);
655	if (success)
656		return (result);
657	if (class < 0 || class > 0xffff)
658		return ("BADCLASS");
659	sprintf(classbuf, "CLASS%d", class);
660	return (classbuf);
661}
662
663/*%
664 * Return a mnemonic for an option
665 */
666const char *
667p_option(u_long option) {
668	char *nbuf = p_option_nbuf;
669
670	switch (option) {
671	case RES_INIT:		return "init";
672	case RES_DEBUG:		return "debug";
673	case RES_AAONLY:	return "aaonly(unimpl)";
674	case RES_USEVC:		return "usevc";
675	case RES_PRIMARY:	return "primry(unimpl)";
676	case RES_IGNTC:		return "igntc";
677	case RES_RECURSE:	return "recurs";
678	case RES_DEFNAMES:	return "defnam";
679	case RES_STAYOPEN:	return "styopn";
680	case RES_DNSRCH:	return "dnsrch";
681	case RES_INSECURE1:	return "insecure1";
682	case RES_INSECURE2:	return "insecure2";
683	case RES_NOALIASES:	return "noaliases";
684	case RES_USE_INET6:	return "inet6";
685#ifdef RES_USE_EDNS0	/*%< KAME extension */
686	case RES_USE_EDNS0:	return "edns0";
687	case RES_NSID:		return "nsid";
688#endif
689#ifdef RES_USE_DNAME
690	case RES_USE_DNAME:	return "dname";
691#endif
692#ifdef RES_USE_DNSSEC
693	case RES_USE_DNSSEC:	return "dnssec";
694#endif
695#ifdef RES_NOTLDQUERY
696	case RES_NOTLDQUERY:	return "no-tld-query";
697#endif
698#ifdef RES_NO_NIBBLE2
699	case RES_NO_NIBBLE2:	return "no-nibble2";
700#endif
701				/* XXX nonreentrant */
702	default:		sprintf(nbuf, "?0x%lx?", (u_long)option);
703				return (nbuf);
704	}
705}
706
707/*%
708 * Return a mnemonic for a time to live.
709 */
710const char *
711p_time(u_int32_t value) {
712	char *nbuf = p_time_nbuf;
713
714	if (ns_format_ttl(value, nbuf, sizeof nbuf) < 0)
715		sprintf(nbuf, "%u", value);
716	return (nbuf);
717}
718
719/*%
720 * Return a string for the rcode.
721 */
722const char *
723p_rcode(int rcode) {
724	return (sym_ntos(__p_rcode_syms, rcode, (int *)0));
725}
726
727/*%
728 * Return a string for a res_sockaddr_union.
729 */
730const char *
731p_sockun(union res_sockaddr_union u, char *buf, size_t size) {
732	char ret[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:123.123.123.123"];
733
734	switch (u.sin.sin_family) {
735	case AF_INET:
736		inet_ntop(AF_INET, &u.sin.sin_addr, ret, sizeof ret);
737		break;
738#ifdef HAS_INET6_STRUCTS
739	case AF_INET6:
740		inet_ntop(AF_INET6, &u.sin6.sin6_addr, ret, sizeof ret);
741		break;
742#endif
743	default:
744		sprintf(ret, "[af%d]", u.sin.sin_family);
745		break;
746	}
747	if (size > 0U) {
748		strncpy(buf, ret, size - 1);
749		buf[size - 1] = '0';
750	}
751	return (buf);
752}
753
754/*%
755 * routines to convert between on-the-wire RR format and zone file format.
756 * Does not contain conversion to/from decimal degrees; divide or multiply
757 * by 60*60*1000 for that.
758 */
759
760static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
761				      1000000,10000000,100000000,1000000000};
762
763/*% takes an XeY precision/size value, returns a string representation. */
764static const char *
765precsize_ntoa(prec)
766	u_int8_t prec;
767{
768	char *retbuf = precsize_ntoa_retbuf;
769	unsigned long val;
770	int mantissa, exponent;
771
772	mantissa = (int)((prec >> 4) & 0x0f) % 10;
773	exponent = (int)((prec >> 0) & 0x0f) % 10;
774
775	val = mantissa * poweroften[exponent];
776
777	(void) sprintf(retbuf, "%lu.%.2lu", val/100, val%100);
778	return (retbuf);
779}
780
781/*% converts ascii size/precision X * 10**Y(cm) to 0xXY.  moves pointer.  */
782static u_int8_t
783precsize_aton(const char **strptr) {
784	unsigned int mval = 0, cmval = 0;
785	u_int8_t retval = 0;
786	const char *cp;
787	int exponent;
788	int mantissa;
789
790	cp = *strptr;
791
792	while (isdigit((unsigned char)*cp))
793		mval = mval * 10 + (*cp++ - '0');
794
795	if (*cp == '.') {		/*%< centimeters */
796		cp++;
797		if (isdigit((unsigned char)*cp)) {
798			cmval = (*cp++ - '0') * 10;
799			if (isdigit((unsigned char)*cp)) {
800				cmval += (*cp++ - '0');
801			}
802		}
803	}
804	cmval = (mval * 100) + cmval;
805
806	for (exponent = 0; exponent < 9; exponent++)
807		if (cmval < poweroften[exponent+1])
808			break;
809
810	mantissa = cmval / poweroften[exponent];
811	if (mantissa > 9)
812		mantissa = 9;
813
814	retval = (mantissa << 4) | exponent;
815
816	*strptr = cp;
817
818	return (retval);
819}
820
821/*% converts ascii lat/lon to unsigned encoded 32-bit number.  moves pointer. */
822static u_int32_t
823latlon2ul(const char **latlonstrptr, int *which) {
824	const char *cp;
825	u_int32_t retval;
826	int deg = 0, min = 0, secs = 0, secsfrac = 0;
827
828	cp = *latlonstrptr;
829
830	while (isdigit((unsigned char)*cp))
831		deg = deg * 10 + (*cp++ - '0');
832
833	while (isspace((unsigned char)*cp))
834		cp++;
835
836	if (!(isdigit((unsigned char)*cp)))
837		goto fndhemi;
838
839	while (isdigit((unsigned char)*cp))
840		min = min * 10 + (*cp++ - '0');
841
842	while (isspace((unsigned char)*cp))
843		cp++;
844
845	if (!(isdigit((unsigned char)*cp)))
846		goto fndhemi;
847
848	while (isdigit((unsigned char)*cp))
849		secs = secs * 10 + (*cp++ - '0');
850
851	if (*cp == '.') {		/*%< decimal seconds */
852		cp++;
853		if (isdigit((unsigned char)*cp)) {
854			secsfrac = (*cp++ - '0') * 100;
855			if (isdigit((unsigned char)*cp)) {
856				secsfrac += (*cp++ - '0') * 10;
857				if (isdigit((unsigned char)*cp)) {
858					secsfrac += (*cp++ - '0');
859				}
860			}
861		}
862	}
863
864	while (!isspace((unsigned char)*cp))	/*%< if any trailing garbage */
865		cp++;
866
867	while (isspace((unsigned char)*cp))
868		cp++;
869
870 fndhemi:
871	switch (*cp) {
872	case 'N': case 'n':
873	case 'E': case 'e':
874		retval = ((unsigned)1<<31)
875			+ (((((deg * 60) + min) * 60) + secs) * 1000)
876			+ secsfrac;
877		break;
878	case 'S': case 's':
879	case 'W': case 'w':
880		retval = ((unsigned)1<<31)
881			- (((((deg * 60) + min) * 60) + secs) * 1000)
882			- secsfrac;
883		break;
884	default:
885		retval = 0;	/*%< invalid value -- indicates error */
886		break;
887	}
888
889	switch (*cp) {
890	case 'N': case 'n':
891	case 'S': case 's':
892		*which = 1;	/*%< latitude */
893		break;
894	case 'E': case 'e':
895	case 'W': case 'w':
896		*which = 2;	/*%< longitude */
897		break;
898	default:
899		*which = 0;	/*%< error */
900		break;
901	}
902
903	cp++;			/*%< skip the hemisphere */
904	while (!isspace((unsigned char)*cp))	/*%< if any trailing garbage */
905		cp++;
906
907	while (isspace((unsigned char)*cp))	/*%< move to next field */
908		cp++;
909
910	*latlonstrptr = cp;
911
912	return (retval);
913}
914
915/*%
916 * converts a zone file representation in a string to an RDATA on-the-wire
917 * representation. */
918int
919loc_aton(ascii, binary)
920	const char *ascii;
921	u_char *binary;
922{
923	const char *cp, *maxcp;
924	u_char *bcp;
925
926	u_int32_t latit = 0, longit = 0, alt = 0;
927	u_int32_t lltemp1 = 0, lltemp2 = 0;
928	int altmeters = 0, altfrac = 0, altsign = 1;
929	u_int8_t hp = 0x16;	/*%< default = 1e6 cm = 10000.00m = 10km */
930	u_int8_t vp = 0x13;	/*%< default = 1e3 cm = 10.00m */
931	u_int8_t siz = 0x12;	/*%< default = 1e2 cm = 1.00m */
932	int which1 = 0, which2 = 0;
933
934	cp = ascii;
935	maxcp = cp + strlen(ascii);
936
937	lltemp1 = latlon2ul(&cp, &which1);
938
939	lltemp2 = latlon2ul(&cp, &which2);
940
941	switch (which1 + which2) {
942	case 3:			/*%< 1 + 2, the only valid combination */
943		if ((which1 == 1) && (which2 == 2)) { /*%< normal case */
944			latit = lltemp1;
945			longit = lltemp2;
946		} else if ((which1 == 2) && (which2 == 1)) { /*%< reversed */
947			longit = lltemp1;
948			latit = lltemp2;
949		} else {	/*%< some kind of brokenness */
950			return (0);
951		}
952		break;
953	default:		/*%< we didn't get one of each */
954		return (0);
955	}
956
957	/* altitude */
958	if (*cp == '-') {
959		altsign = -1;
960		cp++;
961	}
962
963	if (*cp == '+')
964		cp++;
965
966	while (isdigit((unsigned char)*cp))
967		altmeters = altmeters * 10 + (*cp++ - '0');
968
969	if (*cp == '.') {		/*%< decimal meters */
970		cp++;
971		if (isdigit((unsigned char)*cp)) {
972			altfrac = (*cp++ - '0') * 10;
973			if (isdigit((unsigned char)*cp)) {
974				altfrac += (*cp++ - '0');
975			}
976		}
977	}
978
979	alt = (10000000 + (altsign * (altmeters * 100 + altfrac)));
980
981	while (!isspace((unsigned char)*cp) && (cp < maxcp)) /*%< if trailing garbage or m */
982		cp++;
983
984	while (isspace((unsigned char)*cp) && (cp < maxcp))
985		cp++;
986
987	if (cp >= maxcp)
988		goto defaults;
989
990	siz = precsize_aton(&cp);
991
992	while (!isspace((unsigned char)*cp) && (cp < maxcp))	/*%< if trailing garbage or m */
993		cp++;
994
995	while (isspace((unsigned char)*cp) && (cp < maxcp))
996		cp++;
997
998	if (cp >= maxcp)
999		goto defaults;
1000
1001	hp = precsize_aton(&cp);
1002
1003	while (!isspace((unsigned char)*cp) && (cp < maxcp))	/*%< if trailing garbage or m */
1004		cp++;
1005
1006	while (isspace((unsigned char)*cp) && (cp < maxcp))
1007		cp++;
1008
1009	if (cp >= maxcp)
1010		goto defaults;
1011
1012	vp = precsize_aton(&cp);
1013
1014 defaults:
1015
1016	bcp = binary;
1017	*bcp++ = (u_int8_t) 0;	/*%< version byte */
1018	*bcp++ = siz;
1019	*bcp++ = hp;
1020	*bcp++ = vp;
1021	PUTLONG(latit,bcp);
1022	PUTLONG(longit,bcp);
1023	PUTLONG(alt,bcp);
1024
1025	return (16);		/*%< size of RR in octets */
1026}
1027
1028/*% takes an on-the-wire LOC RR and formats it in a human readable format. */
1029const char *
1030loc_ntoa(binary, ascii)
1031	const u_char *binary;
1032	char *ascii;
1033{
1034	static const char *error = "?";
1035	static char tmpbuf[sizeof
1036"1000 60 60.000 N 1000 60 60.000 W -12345678.00m 90000000.00m 90000000.00m 90000000.00m"];
1037	const u_char *cp = binary;
1038
1039	int latdeg, latmin, latsec, latsecfrac;
1040	int longdeg, longmin, longsec, longsecfrac;
1041	char northsouth, eastwest;
1042	const char *altsign;
1043	int altmeters, altfrac;
1044
1045	const u_int32_t referencealt = 100000 * 100;
1046
1047	int32_t latval, longval, altval;
1048	u_int32_t templ;
1049	u_int8_t sizeval, hpval, vpval, versionval;
1050
1051	char *sizestr, *hpstr, *vpstr;
1052
1053	versionval = *cp++;
1054
1055	if (ascii == NULL)
1056		ascii = tmpbuf;
1057
1058	if (versionval) {
1059		(void) sprintf(ascii, "; error: unknown LOC RR version");
1060		return (ascii);
1061	}
1062
1063	sizeval = *cp++;
1064
1065	hpval = *cp++;
1066	vpval = *cp++;
1067
1068	GETLONG(templ, cp);
1069	latval = (templ - ((unsigned)1<<31));
1070
1071	GETLONG(templ, cp);
1072	longval = (templ - ((unsigned)1<<31));
1073
1074	GETLONG(templ, cp);
1075	if (templ < referencealt) { /*%< below WGS 84 spheroid */
1076		altval = referencealt - templ;
1077		altsign = "-";
1078	} else {
1079		altval = templ - referencealt;
1080		altsign = "";
1081	}
1082
1083	if (latval < 0) {
1084		northsouth = 'S';
1085		latval = -latval;
1086	} else
1087		northsouth = 'N';
1088
1089	latsecfrac = latval % 1000;
1090	latval = latval / 1000;
1091	latsec = latval % 60;
1092	latval = latval / 60;
1093	latmin = latval % 60;
1094	latval = latval / 60;
1095	latdeg = latval;
1096
1097	if (longval < 0) {
1098		eastwest = 'W';
1099		longval = -longval;
1100	} else
1101		eastwest = 'E';
1102
1103	longsecfrac = longval % 1000;
1104	longval = longval / 1000;
1105	longsec = longval % 60;
1106	longval = longval / 60;
1107	longmin = longval % 60;
1108	longval = longval / 60;
1109	longdeg = longval;
1110
1111	altfrac = altval % 100;
1112	altmeters = (altval / 100);
1113
1114	sizestr = strdup(precsize_ntoa(sizeval));
1115	hpstr = strdup(precsize_ntoa(hpval));
1116	vpstr = strdup(precsize_ntoa(vpval));
1117
1118	sprintf(ascii,
1119	    "%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %s%d.%.2dm %sm %sm %sm",
1120		latdeg, latmin, latsec, latsecfrac, northsouth,
1121		longdeg, longmin, longsec, longsecfrac, eastwest,
1122		altsign, altmeters, altfrac,
1123		(sizestr != NULL) ? sizestr : error,
1124		(hpstr != NULL) ? hpstr : error,
1125		(vpstr != NULL) ? vpstr : error);
1126
1127	if (sizestr != NULL)
1128		free(sizestr);
1129	if (hpstr != NULL)
1130		free(hpstr);
1131	if (vpstr != NULL)
1132		free(vpstr);
1133
1134	return (ascii);
1135}
1136
1137
1138/*% Return the number of DNS hierarchy levels in the name. */
1139int
1140dn_count_labels(const char *name) {
1141	int i, len, count;
1142
1143	len = strlen(name);
1144	for (i = 0, count = 0; i < len; i++) {
1145		/* XXX need to check for \. or use named's nlabels(). */
1146		if (name[i] == '.')
1147			count++;
1148	}
1149
1150	/* don't count initial wildcard */
1151	if (name[0] == '*')
1152		if (count)
1153			count--;
1154
1155	/* don't count the null label for root. */
1156	/* if terminating '.' not found, must adjust */
1157	/* count to include last label */
1158	if (len > 0 && name[len-1] != '.')
1159		count++;
1160	return (count);
1161}
1162
1163/*%
1164 * Make dates expressed in seconds-since-Jan-1-1970 easy to read.
1165 * SIG records are required to be printed like this, by the Secure DNS RFC.
1166 */
1167char *
1168p_secstodate (u_long secs) {
1169	char *output = p_secstodate_output;
1170	time_t clock = secs;
1171	struct tm *time;
1172#ifdef HAVE_TIME_R
1173	struct tm res;
1174
1175	time = gmtime_r(&clock, &res);
1176#else
1177	time = gmtime(&clock);
1178#endif
1179	time->tm_year += 1900;
1180	time->tm_mon += 1;
1181	sprintf(output, "%04d%02d%02d%02d%02d%02d",
1182		time->tm_year, time->tm_mon, time->tm_mday,
1183		time->tm_hour, time->tm_min, time->tm_sec);
1184	return (output);
1185}
1186
1187u_int16_t
1188res_nametoclass(const char *buf, int *successp) {
1189	unsigned long result;
1190	char *endptr;
1191	int success;
1192
1193	result = sym_ston(__p_class_syms, buf, &success);
1194	if (success)
1195		goto done;
1196
1197	if (strncasecmp(buf, "CLASS", 5) != 0 ||
1198	    !isdigit((unsigned char)buf[5]))
1199		goto done;
1200	errno = 0;
1201	result = strtoul(buf + 5, &endptr, 10);
1202	if (errno == 0 && *endptr == '\0' && result <= 0xffffU)
1203		success = 1;
1204 done:
1205	if (successp)
1206		*successp = success;
1207	return (result);
1208}
1209
1210u_int16_t
1211res_nametotype(const char *buf, int *successp) {
1212	unsigned long result;
1213	char *endptr;
1214	int success;
1215
1216	result = sym_ston(__p_type_syms, buf, &success);
1217	if (success)
1218		goto done;
1219
1220	if (strncasecmp(buf, "type", 4) != 0 ||
1221	    !isdigit((unsigned char)buf[4]))
1222		goto done;
1223	errno = 0;
1224	result = strtoul(buf + 4, &endptr, 10);
1225	if (errno == 0 && *endptr == '\0' && result <= 0xffffU)
1226		success = 1;
1227 done:
1228	if (successp)
1229		*successp = success;
1230	return (result);
1231}
1232
1233/*! \file */
1234