1 /*	$OpenBSD: res_debug.c,v 1.17 2003/06/02 20:18:36 millert Exp $	*/
2 
3 /*
4  * ++Copyright++ 1985, 1990, 1993
5  * -
6  * Copyright (c) 1985, 1990, 1993
7  *    The Regents of the University of California.  All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. 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  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
34  *
35  * Permission to use, copy, modify, and distribute this software for any
36  * purpose with or without fee is hereby granted, provided that the above
37  * copyright notice and this permission notice appear in all copies, and that
38  * the name of Digital Equipment Corporation not be used in advertising or
39  * publicity pertaining to distribution of the document or software without
40  * specific, written prior permission.
41  *
42  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
43  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
44  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
45  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
46  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
47  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
48  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
49  * SOFTWARE.
50  * -
51  * Portions Copyright (c) 1995 by International Business Machines, Inc.
52  *
53  * International Business Machines, Inc. (hereinafter called IBM) grants
54  * permission under its copyrights to use, copy, modify, and distribute this
55  * Software with or without fee, provided that the above copyright notice and
56  * all paragraphs of this notice appear in all copies, and that the name of IBM
57  * not be used in connection with the marketing of any product incorporating
58  * the Software or modifications thereof, without specific, written prior
59  * permission.
60  *
61  * To the extent it has a right to do so, IBM grants an immunity from suit
62  * under its patents, if any, for the use, sale or manufacture of products to
63  * the extent that such products are used for performing Domain Name System
64  * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
65  * granted for any product per se or for any other function of any product.
66  *
67  * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
68  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
69  * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
70  * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
71  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
72  * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
73  * --Copyright--
74  */
75 
76 #include <sys/param.h>
77 #include <sys/types.h>
78 #include <sys/time.h>
79 #include <sys/socket.h>
80 #include <netinet/in.h>
81 #include <arpa/inet.h>
82 #include <arpa/nameser.h>
83 
84 #include <ctype.h>
85 #include <stdio.h>
86 #include <time.h>
87 
88 #include <stdlib.h>
89 #include <string.h>
90 #include <event.h>
91 
92 #include "dnsres.h"
93 #include "dnsres-internal.h"
94 #include "resolv.h"
95 
96 /* Signatures */
97                                         /* Size of a mod or exp in bits */
98 #define MIN_MD5RSA_KEY_PART_BITS         512
99 #define MAX_MD5RSA_KEY_PART_BITS        2552
100                                         /* Total of binary mod and exp, bytes */
101 #define MAX_MD5RSA_KEY_BYTES            ((MAX_MD5RSA_KEY_PART_BITS+7/8)*2+3)
102                                         /* Max length of text sig block */
103 #define MAX_KEY_BASE64                  (((MAX_MD5RSA_KEY_BYTES+2)/3)*4)
104 
105 extern const char *dnsres_opcodes[];
106 extern const char *dnsres_resultcodes[];
107 
108 static const char *loc_ntoal(const u_char *binary, char *ascii, int ascii_len);
109 
110 /* XXX: we should use getservbyport() instead. */
111 static const char *
dewks(wks)112 dewks(wks)
113 	int wks;
114 {
115 	static char nbuf[20];
116 
117 	switch (wks) {
118 	case 5: return "rje";
119 	case 7: return "echo";
120 	case 9: return "discard";
121 	case 11: return "systat";
122 	case 13: return "daytime";
123 	case 15: return "netstat";
124 	case 17: return "qotd";
125 	case 19: return "chargen";
126 	case 20: return "ftp-data";
127 	case 21: return "ftp";
128 	case 23: return "telnet";
129 	case 25: return "smtp";
130 	case 37: return "time";
131 	case 39: return "rlp";
132 	case 42: return "name";
133 	case 43: return "whois";
134 	case 53: return "domain";
135 	case 57: return "apts";
136 	case 59: return "apfs";
137 	case 67: return "bootps";
138 	case 68: return "bootpc";
139 	case 69: return "tftp";
140 	case 77: return "rje";
141 	case 79: return "finger";
142 	case 87: return "link";
143 	case 95: return "supdup";
144 	case 100: return "newacct";
145 	case 101: return "hostnames";
146 	case 102: return "iso-tsap";
147 	case 103: return "x400";
148 	case 104: return "x400-snd";
149 	case 105: return "csnet-ns";
150 	case 109: return "pop-2";
151 	case 111: return "sunrpc";
152 	case 113: return "auth";
153 	case 115: return "sftp";
154 	case 117: return "uucp-path";
155 	case 119: return "nntp";
156 	case 121: return "erpc";
157 	case 123: return "ntp";
158 	case 133: return "statsrv";
159 	case 136: return "profile";
160 	case 144: return "NeWS";
161 	case 161: return "snmp";
162 	case 162: return "snmp-trap";
163 	case 170: return "print-srv";
164 	default:
165 		(void) snprintf(nbuf, sizeof nbuf, "%d", wks);
166 		return (nbuf);
167 	}
168 }
169 
170 /* XXX: we should use getprotobynumber() instead. */
171 static const char *
deproto(protonum)172 deproto(protonum)
173 	int protonum;
174 {
175 	static char nbuf[20];
176 
177 	switch (protonum) {
178 	case 1: return "icmp";
179 	case 2: return "igmp";
180 	case 3: return "ggp";
181 	case 5: return "st";
182 	case 6: return "tcp";
183 	case 7: return "ucl";
184 	case 8: return "egp";
185 	case 9: return "igp";
186 	case 11: return "nvp-II";
187 	case 12: return "pup";
188 	case 16: return "chaos";
189 	case 17: return "udp";
190 	default:
191 		(void) snprintf(nbuf, sizeof nbuf, "%d", protonum);
192 		return (nbuf);
193 	}
194 }
195 
196 static const u_char *
do_rrset(struct dnsres * _resp,const u_char * msg,int len,const u_char * cp,int cnt,int pflag,FILE * file,const char * hs)197 do_rrset(struct dnsres *_resp,
198     const u_char *msg, int len,
199     const u_char *cp, int cnt, int pflag, FILE *file, const char *hs)
200 {
201 	int n;
202 	int sflag;
203 
204 	/*
205 	 * Print answer records.
206 	 */
207 	sflag = (_resp->pfcode & pflag);
208 	if ((n = ntohs(cnt))) {
209 		if ((!_resp->pfcode) ||
210 		    ((sflag) && (_resp->pfcode & RES_PRF_HEAD1)))
211 			fprintf(file, "%s", hs);
212 		while (--n >= 0) {
213 			if ((!_resp->pfcode) || sflag) {
214 				cp = p_rr(_resp, cp, msg, file);
215 			} else {
216 				unsigned int dlen;
217 				cp += __dnsres_dn_skipname(cp, cp + DNSRES_MAXCDNAME);
218 				cp += DNSRES_INT16SZ;
219 				cp += DNSRES_INT16SZ;
220 				cp += DNSRES_INT32SZ;
221 				dlen = getshort((u_char*)cp);
222 				cp += DNSRES_INT16SZ;
223 				cp += dlen;
224 			}
225 			if ((cp - msg) > len)
226 				return (NULL);
227 		}
228 		if ((!_resp->pfcode) ||
229 		    ((sflag) && (_resp->pfcode & RES_PRF_HEAD1)))
230 			putc('\n', file);
231 	}
232 	return (cp);
233 }
234 
235 void
__dnsres_p_query(struct dnsres * _resp,const u_char * msg)236 __dnsres_p_query(struct dnsres *_resp, const u_char *msg)
237 {
238 	__dnsres_fp_query(_resp, msg, stdout);
239 }
240 
241 /*
242  * Print the current options.
243  * This is intended to be primarily a debugging routine.
244  */
245 void
__dnsres_fp_resstat(statp,file)246 __dnsres_fp_resstat(statp, file)
247 	struct dnsres *statp;
248 	FILE *file;
249 {
250 	register u_long mask;
251 
252 	fprintf(file, ";; res options:");
253 	for (mask = 1;  mask != 0;  mask <<= 1)
254 		if (statp->options & mask)
255 			fprintf(file, " %s", p_option(mask));
256 	putc('\n', file);
257 }
258 
259 /*
260  * Print the contents of a query.
261  * This is intended to be primarily a debugging routine.
262  */
263 void
__dnsres_fp_nquery(struct dnsres * _resp,const u_char * msg,int len,FILE * file)264 __dnsres_fp_nquery(struct dnsres *_resp,
265     const u_char *msg, int len, FILE *file)
266 {
267 	register const u_char *cp, *endMark;
268 	register const DNSRES_HEADER *hp;
269 	register int n;
270 
271 #define TruncTest(x) if (x > endMark) goto trunc
272 #define	ErrorTest(x) if (x == NULL) goto error
273 
274 	/*
275 	 * Print header fields.
276 	 */
277 	hp = (DNSRES_HEADER *)msg;
278 	cp = msg + DNSRES_HFIXEDSZ;
279 	endMark = msg + len;
280 	if ((!_resp->pfcode) || (_resp->pfcode & RES_PRF_HEADX) || hp->rcode) {
281 		fprintf(file, ";; ->>DNSRES_HEADER<<- opcode: %s, status: %s, id: %u",
282 			dnsres_opcodes[hp->opcode],
283 			dnsres_resultcodes[hp->rcode],
284 			ntohs(hp->id));
285 		putc('\n', file);
286 	}
287 	if ((!_resp->pfcode) || (_resp->pfcode & RES_PRF_HEADX))
288 		putc(';', file);
289 	if ((!_resp->pfcode) || (_resp->pfcode & RES_PRF_HEAD2)) {
290 		fprintf(file, "; flags:");
291 		if (hp->qr)
292 			fprintf(file, " qr");
293 		if (hp->aa)
294 			fprintf(file, " aa");
295 		if (hp->tc)
296 			fprintf(file, " tc");
297 		if (hp->rd)
298 			fprintf(file, " rd");
299 		if (hp->ra)
300 			fprintf(file, " ra");
301 		if (hp->unused)
302 			fprintf(file, " UNUSED-BIT-ON");
303 		if (hp->ad)
304 			fprintf(file, " ad");
305 		if (hp->cd)
306 			fprintf(file, " cd");
307 	}
308 	if ((!_resp->pfcode) || (_resp->pfcode & RES_PRF_HEAD1)) {
309 		fprintf(file, "; Ques: %u", ntohs(hp->qdcount));
310 		fprintf(file, ", Ans: %u", ntohs(hp->ancount));
311 		fprintf(file, ", Auth: %u", ntohs(hp->nscount));
312 		fprintf(file, ", Addit: %u", ntohs(hp->arcount));
313 	}
314 	if ((!_resp->pfcode) || (_resp->pfcode &
315 		(RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) {
316 		putc('\n',file);
317 	}
318 	/*
319 	 * Print question records.
320 	 */
321 	if ((n = ntohs(hp->qdcount))) {
322 		if ((!_resp->pfcode) || (_resp->pfcode & RES_PRF_QUES))
323 			fprintf(file, ";; QUESTIONS:\n");
324 		while (--n >= 0) {
325 			if ((!_resp->pfcode) || (_resp->pfcode & RES_PRF_QUES))
326 				fprintf(file, ";;\t");
327 			TruncTest(cp);
328 			if ((!_resp->pfcode) || (_resp->pfcode & RES_PRF_QUES))
329 				cp = p_cdnname(cp, msg, len, file);
330 			else {
331 				int n;
332 				char name[DNSRES_MAXDNAME];
333 
334 				if ((n = dn_expand(msg, msg+len, cp, name,
335 						sizeof name)) < 0)
336 					cp = NULL;
337 				else
338 					cp += n;
339 			}
340 			ErrorTest(cp);
341 			TruncTest(cp);
342 			if ((!_resp->pfcode) || (_resp->pfcode & RES_PRF_QUES))
343 				fprintf(file, ", type = %s",
344 					__dnsres_p_type(getshort((u_char*)cp)));
345 			cp += DNSRES_INT16SZ;
346 			TruncTest(cp);
347 			if ((!_resp->pfcode) || (_resp->pfcode & RES_PRF_QUES))
348 				fprintf(file, ", class = %s\n",
349 					__dnsres_p_class(getshort((u_char*)cp)));
350 			cp += DNSRES_INT16SZ;
351 			if ((!_resp->pfcode) || (_resp->pfcode & RES_PRF_QUES))
352 				putc('\n', file);
353 		}
354 	}
355 	/*
356 	 * Print authoritative answer records
357 	 */
358 	TruncTest(cp);
359 	cp = do_rrset(_resp, msg, len, cp, hp->ancount, RES_PRF_ANS, file,
360 	    ";; ANSWERS:\n");
361 	ErrorTest(cp);
362 
363 	/*
364 	 * print name server records
365 	 */
366 	TruncTest(cp);
367 	cp = do_rrset(_resp, msg, len, cp, hp->nscount, RES_PRF_AUTH, file,
368 		      ";; AUTHORITY RECORDS:\n");
369 	ErrorTest(cp);
370 
371 	TruncTest(cp);
372 	/*
373 	 * print additional records
374 	 */
375 	cp = do_rrset(_resp, msg, len, cp, hp->arcount, RES_PRF_ADD, file,
376 		      ";; ADDITIONAL RECORDS:\n");
377 	ErrorTest(cp);
378 	return;
379  trunc:
380 	fprintf(file, "\n;; ...truncated\n");
381 	return;
382  error:
383 	fprintf(file, "\n;; ...malformed\n");
384 }
385 
386 void
__dnsres_fp_query(struct dnsres * _resp,const u_char * msg,FILE * file)387 __dnsres_fp_query(struct dnsres *_resp, const u_char *msg, FILE *file)
388 {
389 	fp_nquery(_resp, msg, DNSRES_PACKETSZ, file);
390 }
391 
392 const u_char *
__dnsres_p_cdnname(cp,msg,len,file)393 __dnsres_p_cdnname(cp, msg, len, file)
394 	const u_char *cp, *msg;
395 	int len;
396 	FILE *file;
397 {
398 	char name[DNSRES_MAXDNAME];
399 	int n;
400 
401 	if ((n = dn_expand(msg, msg + len, cp, name, sizeof name)) < 0)
402 		return (NULL);
403 	if (name[0] == '\0')
404 		putc('.', file);
405 	else
406 		fputs(name, file);
407 	return (cp + n);
408 }
409 
410 const u_char *
__dnsres_p_cdname(cp,msg,file)411 __dnsres_p_cdname(cp, msg, file)
412 	const u_char *cp, *msg;
413 	FILE *file;
414 {
415 	return (p_cdnname(cp, msg, DNSRES_PACKETSZ, file));
416 }
417 
418 
419 /* Return a fully-qualified domain name from a compressed name (with
420    length supplied).  */
421 
422 const u_char *
__dnsres_p_fqnname(cp,msg,msglen,name,namelen)423 __dnsres_p_fqnname(cp, msg, msglen, name, namelen)
424 	const u_char *cp, *msg;
425 	int msglen;
426 	char *name;
427 	int namelen;
428 {
429 	int n, newlen;
430 
431 	if ((n = dn_expand(msg, cp + msglen, cp, name, namelen)) < 0)
432 		return (NULL);
433 	newlen = strlen(name);
434 	if (newlen == 0 || name[newlen - 1] != '.') {
435 		if (newlen + 1 >= namelen)	/* Lack space for final dot */
436 			return (NULL);
437 		else
438 			strlcpy(name + newlen, ".", namelen - newlen);
439 	}
440 	return (cp + n);
441 }
442 
443 /* XXX:	the rest of these functions need to become length-limited, too. (vix)
444  */
445 
446 const u_char *
__dnsres_p_fqname(cp,msg,file)447 __dnsres_p_fqname(cp, msg, file)
448 	const u_char *cp, *msg;
449 	FILE *file;
450 {
451 	char name[DNSRES_MAXDNAME];
452 	const u_char *n;
453 
454 	n = __dnsres_p_fqnname(cp, msg, DNSRES_MAXCDNAME, name, sizeof name);
455 	if (n == NULL)
456 		return (NULL);
457 	fputs(name, file);
458 	return (n);
459 }
460 
461 /*
462  * Print resource record fields in human readable form.
463  */
464 const u_char *
__dnsres_p_rr(struct dnsres * _resp,const u_char * cp,const u_char * msg,FILE * file)465 __dnsres_p_rr(struct dnsres *_resp,
466     const u_char *cp, const u_char *msg, FILE *file)
467 {
468 	int type, class, dlen, n, c;
469 	struct in_addr inaddr;
470 	const u_char *cp1, *cp2;
471 	u_int32_t tmpttl, t;
472 	int lcnt;
473 	u_int16_t keyflags;
474 	char rrname[DNSRES_MAXDNAME];		/* The fqdn of this RR */
475 	char base64_key[MAX_KEY_BASE64];
476 
477 	cp = __dnsres_p_fqnname(cp, msg, DNSRES_MAXCDNAME, rrname, sizeof rrname);
478 	if (!cp)
479 		return (NULL);			/* compression error */
480 	fputs(rrname, file);
481 
482 	type = getshort((u_char*)cp);
483 	cp += DNSRES_INT16SZ;
484 	class = getshort((u_char*)cp);
485 	cp += DNSRES_INT16SZ;
486 	tmpttl = getlong((u_char*)cp);
487 	cp += DNSRES_INT32SZ;
488 	dlen = getshort((u_char*)cp);
489 	cp += DNSRES_INT16SZ;
490 	cp1 = cp;
491 	if ((!_resp->pfcode) || (_resp->pfcode & RES_PRF_TTLID))
492 		fprintf(file, "\t%lu", (u_long)tmpttl);
493 	if ((!_resp->pfcode) || (_resp->pfcode & RES_PRF_CLASS))
494 		fprintf(file, "\t%s", __dnsres_p_class(class));
495 	fprintf(file, "\t%s", __dnsres_p_type(type));
496 	/*
497 	 * Print type specific data, if appropriate
498 	 */
499 	switch (type) {
500 	case DNSRES_T_A:
501 		switch (class) {
502 		case DNSRES_C_IN:
503 		case DNSRES_C_HS:
504 			bcopy(cp, (char *)&inaddr, INADDRSZ);
505 			if (dlen == 4) {
506 				fprintf(file, "\t%s", inet_ntoa(inaddr));
507 				cp += dlen;
508 			} else if (dlen == 7) {
509 				char *address;
510 				u_char protocol;
511 				in_port_t port;
512 
513 				address = inet_ntoa(inaddr);
514 				cp += INADDRSZ;
515 				protocol = *(u_char*)cp;
516 				cp += sizeof (u_char);
517 				port = getshort((u_char*)cp);
518 				cp += DNSRES_INT16SZ;
519 				fprintf(file, "\t%s\t; proto %u, port %u",
520 					address, protocol, port);
521 			}
522 			break;
523 		default:
524 			cp += dlen;
525 		}
526 		break;
527 	case DNSRES_T_CNAME:
528 	case DNSRES_T_MB:
529 	case DNSRES_T_MG:
530 	case DNSRES_T_MR:
531 	case DNSRES_T_NS:
532 	case DNSRES_T_PTR:
533 		putc('\t', file);
534 		if ((cp = p_fqname(cp, msg, file)) == NULL)
535 			return (NULL);
536 		break;
537 
538 	case DNSRES_T_HINFO:
539 	case DNSRES_T_ISDN:
540 		cp2 = cp + dlen;
541 		(void) fputs("\t\"", file);
542 		if ((n = (unsigned char) *cp++) != 0) {
543 			for (c = n; c > 0 && cp < cp2; c--) {
544 				if (strchr("\n\"\\", *cp))
545 					(void) putc('\\', file);
546 				(void) putc(*cp++, file);
547 			}
548 		}
549 		putc('"', file);
550 		if (cp < cp2 && (n = (unsigned char) *cp++) != 0) {
551 			(void) fputs ("\t\"", file);
552 			for (c = n; c > 0 && cp < cp2; c--) {
553 				if (strchr("\n\"\\", *cp))
554 					(void) putc('\\', file);
555 				(void) putc(*cp++, file);
556 			}
557 			putc('"', file);
558 		} else if (type == DNSRES_T_HINFO) {
559 			(void) fputs("\"?\"", file);
560 			fprintf(file, "\n;; *** Warning *** OS-type missing");
561 		}
562 		break;
563 
564 	case DNSRES_T_SOA:
565 		putc('\t', file);
566 		if ((cp = p_fqname(cp, msg, file)) == NULL)
567 			return (NULL);
568 		putc(' ', file);
569 		if ((cp = p_fqname(cp, msg, file)) == NULL)
570 			return (NULL);
571 		fputs(" (\n", file);
572 		t = getlong((u_char*)cp);  cp += DNSRES_INT32SZ;
573 		fprintf(file, "\t\t\t%lu\t; serial\n", (u_long)t);
574 		t = getlong((u_char*)cp);  cp += DNSRES_INT32SZ;
575 		fprintf(file, "\t\t\t%lu\t; refresh (%s)\n",
576 			(u_long)t, __dnsres_p_time(t));
577 		t = getlong((u_char*)cp);  cp += DNSRES_INT32SZ;
578 		fprintf(file, "\t\t\t%lu\t; retry (%s)\n",
579 			(u_long)t, __dnsres_p_time(t));
580 		t = getlong((u_char*)cp);  cp += DNSRES_INT32SZ;
581 		fprintf(file, "\t\t\t%lu\t; expire (%s)\n",
582 			(u_long)t, __dnsres_p_time(t));
583 		t = getlong((u_char*)cp);  cp += DNSRES_INT32SZ;
584 		fprintf(file, "\t\t\t%lu )\t; minimum (%s)",
585 			(u_long)t, __dnsres_p_time(t));
586 		break;
587 
588 	case DNSRES_T_MX:
589 	case DNSRES_T_AFSDB:
590 	case DNSRES_T_RT:
591 		fprintf(file, "\t%u ", getshort((u_char*)cp));
592 		cp += DNSRES_INT16SZ;
593 		if ((cp = p_fqname(cp, msg, file)) == NULL)
594 			return (NULL);
595 		break;
596 
597 	case DNSRES_T_PX:
598 		fprintf(file, "\t%u ", getshort((u_char*)cp));
599 		cp += DNSRES_INT16SZ;
600 		if ((cp = p_fqname(cp, msg, file)) == NULL)
601 			return (NULL);
602 		putc(' ', file);
603 		if ((cp = p_fqname(cp, msg, file)) == NULL)
604 			return (NULL);
605 		break;
606 
607 	case DNSRES_T_X25:
608 		cp2 = cp + dlen;
609 		(void) fputs("\t\"", file);
610 		if ((n = (unsigned char) *cp++) != 0) {
611 			for (c = n; c > 0 && cp < cp2; c--) {
612 				if (strchr("\n\"\\", *cp))
613 					(void) putc('\\', file);
614 				(void) putc(*cp++, file);
615 			}
616 		}
617 		putc('"', file);
618 		break;
619 
620 	case DNSRES_T_TXT:
621 		(void) putc('\t', file);
622 		cp2 = cp1 + dlen;
623 		while (cp < cp2) {
624 			putc('"', file);
625 			if ((n = (unsigned char) *cp++)) {
626 				for (c = n; c > 0 && cp < cp2; c--) {
627 					if (strchr("\n\"\\", *cp))
628 						(void) putc('\\', file);
629 					(void) putc(*cp++, file);
630 				}
631 			}
632 			putc('"', file);
633 			if (cp < cp2)
634 				putc(' ', file);
635 		}
636 		break;
637 
638 	case DNSRES_T_NSAP:
639 		(void) fprintf(file, "\t%s", inet_nsap_ntoa(dlen, cp, NULL));
640 		cp += dlen;
641 		break;
642 
643 	case DNSRES_T_AAAA: {
644 		char t[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
645 
646 		fprintf(file, "\t%s", inet_ntop(AF_INET6, cp, t, sizeof t));
647 		cp += dlen;
648 		break;
649 	    }
650 
651 	case DNSRES_T_LOC: {
652 		char t[255];
653 
654 		fprintf(file, "\t%s", loc_ntoal(cp, t, sizeof t));
655 		cp += dlen;
656 		break;
657 	    }
658 
659 	case DNSRES_T_NAPTR: {
660 		u_int order, preference;
661 
662 		order = getshort(cp);  cp += DNSRES_INT16SZ;
663 		preference   = getshort(cp);  cp += DNSRES_INT16SZ;
664 		fprintf(file, "\t%u %u ",order, preference);
665 		/* Flags */
666 		n = *cp++;
667 		fprintf(file,"\"%.*s\" ", (int)n, cp);
668 		cp += n;
669 		/* Service */
670 		n = *cp++;
671 		fprintf(file,"\"%.*s\" ", (int)n, cp);
672 		cp += n;
673 		/* Regexp */
674 		n = *cp++;
675 		fprintf(file,"\"%.*s\" ", (int)n, cp);
676 		cp += n;
677 		if ((cp = p_fqname(cp, msg, file)) == NULL)
678 			return (NULL);
679 		break;
680 	    }
681 
682 	case DNSRES_T_SRV: {
683 		u_int priority, weight, port;
684 
685 		priority = getshort(cp);  cp += DNSRES_INT16SZ;
686 		weight   = getshort(cp);  cp += DNSRES_INT16SZ;
687 		port     = getshort(cp);  cp += DNSRES_INT16SZ;
688 		fprintf(file, "\t%u %u %u ", priority, weight, port);
689 		if ((cp = p_fqname(cp, msg, file)) == NULL)
690 			return (NULL);
691 		break;
692 	    }
693 
694 	case DNSRES_T_MINFO:
695 	case DNSRES_T_RP:
696 		putc('\t', file);
697 		if ((cp = p_fqname(cp, msg, file)) == NULL)
698 			return (NULL);
699 		putc(' ', file);
700 		if ((cp = p_fqname(cp, msg, file)) == NULL)
701 			return (NULL);
702 		break;
703 #ifdef DNSRES_T_UINFO
704 	case DNSRES_T_UINFO:
705 		putc('\t', file);
706 		fputs((char *)cp, file);
707 		cp += dlen;
708 		break;
709 
710 	case DNSRES_T_UID:
711 	case DNSRES_T_GID:
712 		if (dlen == 4) {
713 			fprintf(file, "\t%u", getlong((u_char*)cp));
714 			cp += DNSRES_INT32SZ;
715 		}
716 		break;
717 #endif
718 	case DNSRES_T_WKS:
719 		if (dlen < DNSRES_INT32SZ + 1)
720 			break;
721 		bcopy(cp, (char *)&inaddr, INADDRSZ);
722 		cp += DNSRES_INT32SZ;
723 		fprintf(file, "\t%s %s ( ",
724 			inet_ntoa(inaddr),
725 			deproto((int) *cp));
726 		cp += sizeof (u_char);
727 		n = 0;
728 		lcnt = 0;
729 		while (cp < cp1 + dlen) {
730 			c = *cp++;
731 			do {
732 				if (c & 0200) {
733 					if (lcnt == 0) {
734 						fputs("\n\t\t\t", file);
735 						lcnt = 5;
736 					}
737 					fputs(dewks(n), file);
738 					putc(' ', file);
739 					lcnt--;
740 				}
741 				c <<= 1;
742 			} while (++n & 07);
743 		}
744 		putc(')', file);
745 		break;
746 
747 	case DNSRES_T_KEY:
748 		putc('\t', file);
749 		keyflags = getshort(cp);
750 		cp += 2;
751 		fprintf(file,"0x%04x", keyflags );	/* flags */
752 		fprintf(file," %u", *cp++);	/* protocol */
753 		fprintf(file," %u (", *cp++);	/* algorithm */
754 
755 		n = b64_ntop(cp, (cp1 + dlen) - cp,
756 			     base64_key, sizeof base64_key);
757 		for (c = 0; c < n; ++c) {
758 			if (0 == (c & 0x3F))
759 				fprintf(file, "\n\t");
760 			putc(base64_key[c], file);  /* public key data */
761 		}
762 
763 		fprintf(file, " )");
764 		if (n < 0)
765 			fprintf(file, "\t; BAD BASE64");
766 		fflush(file);
767 		cp = cp1 + dlen;
768 		break;
769 
770 	case DNSRES_T_SIG:
771 	        type = getshort((u_char*)cp);
772 		cp += DNSRES_INT16SZ;
773 		fprintf(file, " %s", p_type(type));
774 		fprintf(file, "\t%u", *cp++);	/* algorithm */
775 		/* Check label value and print error if wrong. */
776 		n = *cp++;
777 		c = dn_count_labels (rrname);
778 		if (n != c)
779 			fprintf(file, "\t; LABELS WRONG (%d should be %d)\n\t",
780 				n, c);
781 		/* orig ttl */
782 		n = getlong((u_char*)cp);
783 		if (n != tmpttl)
784 			fprintf(file, " %u", n);
785 		cp += DNSRES_INT32SZ;
786 		/* sig expire */
787 		fprintf(file, " (\n\t%s",
788 		    __dnsres_p_secstodate(getlong((u_char*)cp)));
789 		cp += DNSRES_INT32SZ;
790 		/* time signed */
791 		fprintf(file, " %s",
792 		    __dnsres_p_secstodate(getlong((u_char*)cp)));
793 		cp += DNSRES_INT32SZ;
794 		/* sig footprint */
795 		fprintf(file," %u ", getshort((u_char*)cp));
796 		cp += DNSRES_INT16SZ;
797 		/* signer's name */
798 		cp = p_fqname(cp, msg, file);
799 		n = b64_ntop(cp, (cp1 + dlen) - cp,
800 			     base64_key, sizeof base64_key);
801 		for (c = 0; c < n; c++) {
802 			if (0 == (c & 0x3F))
803 				fprintf (file, "\n\t");
804 			putc(base64_key[c], file);		/* signature */
805 		}
806 		/* Clean up... */
807 		fprintf(file, " )");
808 		if (n < 0)
809 			fprintf(file, "\t; BAD BASE64");
810 		fflush(file);
811 		cp = cp1+dlen;
812 		break;
813 
814 #ifdef ALLOW_T_UNSPEC
815 	case DNSRES_T_UNSPEC:
816 		{
817 			int NumBytes = 8;
818 			u_char *DataPtr;
819 			int i;
820 
821 			if (dlen < NumBytes) NumBytes = dlen;
822 			fprintf(file, "\tFirst %d bytes of hex data:",
823 				NumBytes);
824 			for (i = 0, DataPtr = cp; i < NumBytes; i++, DataPtr++)
825 				fprintf(file, " %x", *DataPtr);
826 			cp += dlen;
827 		}
828 		break;
829 #endif /* ALLOW_T_UNSPEC */
830 
831 	default:
832 		fprintf(file, "\t?%d?", type);
833 		cp += dlen;
834 	}
835 #if 0
836 	fprintf(file, "\t; dlen=%d, ttl %s\n", dlen, __dnsres_p_time(tmpttl));
837 #else
838 	putc('\n', file);
839 #endif
840 	if (cp - cp1 != dlen) {
841 		fprintf(file,
842 		    ";; packet size error (found %ld, dlen was %d)\n",
843 			(long)(cp - cp1), dlen);
844 		cp = NULL;
845 	}
846 	return (cp);
847 }
848 
849 /*
850  * Names of RR classes and qclasses.  Classes and qclasses are the same, except
851  * that DNSRES_C_ANY is a qclass but not a class.  (You can ask for records of class
852  * DNSRES_C_ANY, but you can't have any records of that class in the database.)
853  */
854 const struct res_sym __dnsres_p_class_syms[] = {
855 	{DNSRES_C_IN,		"IN"},
856 	{DNSRES_C_CHAOS,	"CHAOS"},
857 	{DNSRES_C_HS,		"HS"},
858 	{DNSRES_C_HS,		"HESIOD"},
859 	{DNSRES_C_ANY,		"ANY"},
860 	{DNSRES_C_IN, 		(char *)0}
861 };
862 
863 /*
864  * Names of RR types and qtypes.  Types and qtypes are the same, except
865  * that T_ANY is a qtype but not a type.  (You can ask for records of type
866  * T_ANY, but you can't have any records of that type in the database.)
867  */
868 const struct res_sym __dnsres_p_type_syms[] = {
869 	{DNSRES_T_A,	"A",		"address"},
870 	{DNSRES_T_NS,	"NS",		"name server"},
871 	{DNSRES_T_MD,	"MD",		"mail destination (deprecated)"},
872 	{DNSRES_T_MF,	"MF",		"mail forwarder (deprecated)"},
873 	{DNSRES_T_CNAME,"CNAME",	"canonical name"},
874 	{DNSRES_T_SOA,	"SOA",		"start of authority"},
875 	{DNSRES_T_MB,	"MB",		"mailbox"},
876 	{DNSRES_T_MG,	"MG",		"mail group member"},
877 	{DNSRES_T_MR,	"MR",		"mail rename"},
878 	{DNSRES_T_NULL,	"NULL",		"null"},
879 	{DNSRES_T_WKS,	"WKS",		"well-known service (deprecated)"},
880 	{DNSRES_T_PTR,	"PTR",		"domain name pointer"},
881 	{DNSRES_T_HINFO,"HINFO",	"host information"},
882 	{DNSRES_T_MINFO,"MINFO",	"mailbox information"},
883 	{DNSRES_T_MX,	"MX",		"mail exchanger"},
884 	{DNSRES_T_TXT,	"TXT",		"text"},
885 	{DNSRES_T_RP,	"RP",		"responsible person"},
886 	{DNSRES_T_AFSDB,"AFSDB",	"DCE or AFS server"},
887 	{DNSRES_T_X25,	"X25",		"X25 address"},
888 	{DNSRES_T_ISDN,	"ISDN",		"ISDN address"},
889 	{DNSRES_T_RT,	"RT",		"router"},
890 	{DNSRES_T_NSAP,	"NSAP",		"nsap address"},
891 	{DNSRES_T_NSAP_PTR,	"NSAP_PTR",	"domain name pointer"},
892 	{DNSRES_T_SIG,	"SIG",		"signature"},
893 	{DNSRES_T_KEY,	"KEY",		"key"},
894 	{DNSRES_T_PX,	"PX",		"mapping information"},
895 	{DNSRES_T_GPOS,	"GPOS",		"geographical position (withdrawn)"},
896 	{DNSRES_T_AAAA,	"AAAA",		"IPv6 address"},
897 	{DNSRES_T_LOC,	"LOC",		"location"},
898 	{DNSRES_T_NXT,	"NXT",		"next valid name (unimplemented)"},
899 	{DNSRES_T_EID,	"EID",		"endpoint identifier (unimplemented)"},
900 	{DNSRES_T_NIMLOC,	"NIMLOC",	"NIMROD locator (unimplemented)"},
901 	{DNSRES_T_SRV,	"SRV",		"server selection"},
902 	{DNSRES_T_ATMA,	"ATMA",		"ATM address (unimplemented)"},
903 	{DNSRES_T_IXFR,	"IXFR",		"incremental zone transfer"},
904 	{DNSRES_T_AXFR,	"AXFR",		"zone transfer"},
905 	{DNSRES_T_MAILB,"MAILB",	"mailbox-related data (deprecated)"},
906 	{DNSRES_T_MAILA,"MAILA",	"mail agent (deprecated)"},
907 #ifdef DNSRES_T_UINFO
908 	{DNSRES_T_UINFO,"UINFO",	"user information (nonstandard)"},
909 	{DNSRES_T_UID,	"UID",		"user ID (nonstandard)"},
910 	{DNSRES_T_GID,	"GID",		"group ID (nonstandard)"},
911 #endif
912 	{DNSRES_T_NAPTR,"NAPTR",	"URN Naming Authority"},
913 #ifdef ALLOW_T_UNSPEC
914 	{DNSRES_T_UNSPEC,"UNSPEC",	"unspecified data (nonstandard)"},
915 #endif /* ALLOW_T_UNSPEC */
916 	{DNSRES_T_ANY,	"ANY",		"\"any\""},
917 	{0, 		NULL,		NULL}
918 };
919 
920 int
__dnsres_sym_ston(syms,name,success)921 __dnsres_sym_ston(syms, name, success)
922 	const struct res_sym *syms;
923 	char *name;
924 	int *success;
925 {
926 	for (; syms->name != 0; syms++) {
927 		if (strcasecmp (name, syms->name) == 0) {
928 			if (success)
929 				*success = 1;
930 			return (syms->number);
931 		}
932 	}
933 	if (success)
934 		*success = 0;
935 	return (syms->number);		/* The default value. */
936 }
937 
938 const char *
__dnsres_sym_ntos(syms,number,success)939 __dnsres_sym_ntos(syms, number, success)
940 	const struct res_sym *syms;
941 	int number;
942 	int *success;
943 {
944 	static char unname[20];
945 
946 	for (; syms->name != 0; syms++) {
947 		if (number == syms->number) {
948 			if (success)
949 				*success = 1;
950 			return (syms->name);
951 		}
952 	}
953 
954 	snprintf(unname, sizeof unname, "%d", number);
955 	if (success)
956 		*success = 0;
957 	return (unname);
958 }
959 
960 
961 const char *
__dnsres_sym_ntop(syms,number,success)962 __dnsres_sym_ntop(syms, number, success)
963 	const struct res_sym *syms;
964 	int number;
965 	int *success;
966 {
967 	static char unname[20];
968 
969 	for (; syms->name != 0; syms++) {
970 		if (number == syms->number) {
971 			if (success)
972 				*success = 1;
973 			return (syms->humanname);
974 		}
975 	}
976 	snprintf(unname, sizeof unname, "%d", number);
977 	if (success)
978 		*success = 0;
979 	return (unname);
980 }
981 
982 /*
983  * Return a string for the type
984  */
985 const char *
__dnsres_p_type(type)986 __dnsres_p_type(type)
987 	int type;
988 {
989 	return (__dnsres_sym_ntos (__dnsres_p_type_syms, type, (int *)0));
990 }
991 
992 /*
993  * Return a mnemonic for class
994  */
995 const char *
__dnsres_p_class(class)996 __dnsres_p_class(class)
997 	int class;
998 {
999 	return (__dnsres_sym_ntos (__dnsres_p_class_syms, class, (int *)0));
1000 }
1001 
1002 /*
1003  * Return a mnemonic for an option
1004  */
1005 const char *
__dnsres_p_option(option)1006 __dnsres_p_option(option)
1007 	u_long option;
1008 {
1009 	static char nbuf[40];
1010 
1011 	switch (option) {
1012 	case RES_INIT:		return "init";
1013 	case RES_DEBUG:		return "debug";
1014 	case RES_AAONLY:	return "aaonly(unimpl)";
1015 	case RES_USEVC:		return "usevc";
1016 	case RES_PRIMARY:	return "primry(unimpl)";
1017 	case RES_IGNTC:		return "igntc";
1018 	case RES_RECURSE:	return "recurs";
1019 	case RES_DEFNAMES:	return "defnam";
1020 	case RES_STAYOPEN:	return "styopn";
1021 	case RES_DNSRCH:	return "dnsrch";
1022 	case RES_INSECURE1:	return "insecure1";
1023 	case RES_INSECURE2:	return "insecure2";
1024 	case RES_USE_INET6:	return "inet6";
1025 	case RES_USE_EDNS0:	return "edns0";
1026 	default:
1027 		snprintf(nbuf, sizeof nbuf, "?0x%lx?", (u_long)option);
1028 		return (nbuf);
1029 	}
1030 }
1031 
1032 /*
1033  * Return a mnemonic for a time to live
1034  */
1035 const char *
p_time(value)1036 p_time(value)
1037 	u_int32_t value;
1038 {
1039 	static char nbuf[40];
1040 	char *ebuf;
1041 	int secs, mins, hours, days;
1042 	register char *p;
1043 	int tmp;
1044 
1045 	if (value == 0) {
1046 		strlcpy(nbuf, "0 secs", sizeof nbuf);
1047 		return (nbuf);
1048 	}
1049 
1050 	secs = value % 60;
1051 	value /= 60;
1052 	mins = value % 60;
1053 	value /= 60;
1054 	hours = value % 24;
1055 	value /= 24;
1056 	days = value;
1057 	value = 0;
1058 
1059 #define	PLURALIZE(x)	x, (x == 1) ? "" : "s"
1060 	p = nbuf;
1061 	ebuf = nbuf + sizeof(nbuf);
1062 	if (days) {
1063 		if ((tmp = snprintf(p, ebuf - p, "%d day%s",
1064 		    PLURALIZE(days))) >= ebuf - nbuf || tmp < 0)
1065 			goto full;
1066 		p += tmp;
1067 	}
1068 	if (hours) {
1069 		if (days)
1070 			*p++ = ' ';
1071 		if (p >= ebuf)
1072 			goto full;
1073 		if ((tmp = snprintf(p, ebuf - p, "%d hour%s",
1074 		    PLURALIZE(hours))) >= ebuf - nbuf || tmp < 0)
1075 			goto full;
1076 		p += tmp;
1077 	}
1078 	if (mins) {
1079 		if (days || hours)
1080 			*p++ = ' ';
1081 		if (p >= ebuf)
1082 			goto full;
1083 		if ((tmp = snprintf(p, ebuf - p, "%d min%s",
1084 		    PLURALIZE(mins))) >= ebuf - nbuf || tmp < 0)
1085 			goto full;
1086 		p += tmp;
1087 	}
1088 	if (secs || ! (days || hours || mins)) {
1089 		if (days || hours || mins)
1090 			*p++ = ' ';
1091 		if (p >= ebuf)
1092 			goto full;
1093 		if ((tmp = snprintf(p, ebuf - p, "%d sec%s",
1094 		    PLURALIZE(secs))) >= ebuf - nbuf || tmp < 0)
1095 			goto full;
1096 	}
1097 	return (nbuf);
1098 full:
1099 	p = nbuf + sizeof(nbuf) - 4;
1100 	*p++ = '.';
1101 	*p++ = '.';
1102 	*p++ = '.';
1103 	*p++ = '\0';
1104 	return (nbuf);
1105 }
1106 
1107 /*
1108  * routines to convert between on-the-wire RR format and zone file format.
1109  * Does not contain conversion to/from decimal degrees; divide or multiply
1110  * by 60*60*1000 for that.
1111  */
1112 
1113 static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
1114 				      1000000,10000000,100000000,1000000000};
1115 
1116 /* takes an XeY precision/size value, returns a string representation. */
1117 static const char *
precsize_ntoa(prec)1118 precsize_ntoa(prec)
1119 	u_int8_t prec;
1120 {
1121 	static char retbuf[sizeof "90000000.00"];
1122 	unsigned long val;
1123 	int mantissa, exponent;
1124 
1125 	mantissa = (int)((prec >> 4) & 0x0f) % 10;
1126 	exponent = (int)((prec >> 0) & 0x0f) % 10;
1127 
1128 	val = mantissa * poweroften[exponent];
1129 
1130 	(void) snprintf(retbuf, sizeof retbuf, "%ld.%.2ld", val/100, val%100);
1131 	return (retbuf);
1132 }
1133 
1134 /* converts ascii size/precision X * 10**Y(cm) to 0xXY.  moves pointer. */
1135 static u_int8_t
precsize_aton(strptr)1136 precsize_aton(strptr)
1137 	char **strptr;
1138 {
1139 	unsigned int mval = 0, cmval = 0;
1140 	u_int8_t retval = 0;
1141 	unsigned char *cp;
1142 	int exponent;
1143 	int mantissa;
1144 
1145 	cp = *strptr;
1146 
1147 	while (isdigit(*cp))
1148 		mval = mval * 10 + (*cp++ - '0');
1149 
1150 	if (*cp == '.') {		/* centimeters */
1151 		cp++;
1152 		if (isdigit(*cp)) {
1153 			cmval = (*cp++ - '0') * 10;
1154 			if (isdigit(*cp)) {
1155 				cmval += (*cp++ - '0');
1156 			}
1157 		}
1158 	}
1159 	cmval = (mval * 100) + cmval;
1160 
1161 	for (exponent = 0; exponent < 9; exponent++)
1162 		if (cmval < poweroften[exponent+1])
1163 			break;
1164 
1165 	mantissa = cmval / poweroften[exponent];
1166 	if (mantissa > 9)
1167 		mantissa = 9;
1168 
1169 	retval = (mantissa << 4) | exponent;
1170 
1171 	*strptr = cp;
1172 
1173 	return (retval);
1174 }
1175 
1176 /* converts ascii lat/lon to unsigned encoded 32-bit number.  moves pointer. */
1177 static u_int32_t
latlon2ul(latlonstrptr,which)1178 latlon2ul(latlonstrptr,which)
1179 	char **latlonstrptr;
1180 	int *which;
1181 {
1182 	unsigned char *cp;
1183 	u_int32_t retval;
1184 	int deg = 0, min = 0, secs = 0, secsfrac = 0;
1185 
1186 	cp = *latlonstrptr;
1187 
1188 	while (isdigit(*cp))
1189 		deg = deg * 10 + (*cp++ - '0');
1190 
1191 	while (isspace(*cp))
1192 		cp++;
1193 
1194 	if (!(isdigit(*cp)))
1195 		goto fndhemi;
1196 
1197 	while (isdigit(*cp))
1198 		min = min * 10 + (*cp++ - '0');
1199 
1200 	while (isspace(*cp))
1201 		cp++;
1202 
1203 	if (!(isdigit(*cp)))
1204 		goto fndhemi;
1205 
1206 	while (isdigit(*cp))
1207 		secs = secs * 10 + (*cp++ - '0');
1208 
1209 	if (*cp == '.') {		/* decimal seconds */
1210 		cp++;
1211 		if (isdigit(*cp)) {
1212 			secsfrac = (*cp++ - '0') * 100;
1213 			if (isdigit(*cp)) {
1214 				secsfrac += (*cp++ - '0') * 10;
1215 				if (isdigit(*cp)) {
1216 					secsfrac += (*cp++ - '0');
1217 				}
1218 			}
1219 		}
1220 	}
1221 
1222 	while (!isspace(*cp))	/* if any trailing garbage */
1223 		cp++;
1224 
1225 	while (isspace(*cp))
1226 		cp++;
1227 
1228  fndhemi:
1229 	switch (*cp) {
1230 	case 'N': case 'n':
1231 	case 'E': case 'e':
1232 		retval = ((unsigned)1<<31)
1233 			+ (((((deg * 60) + min) * 60) + secs) * 1000)
1234 			+ secsfrac;
1235 		break;
1236 	case 'S': case 's':
1237 	case 'W': case 'w':
1238 		retval = ((unsigned)1<<31)
1239 			- (((((deg * 60) + min) * 60) + secs) * 1000)
1240 			- secsfrac;
1241 		break;
1242 	default:
1243 		retval = 0;	/* invalid value -- indicates error */
1244 		break;
1245 	}
1246 
1247 	switch (*cp) {
1248 	case 'N': case 'n':
1249 	case 'S': case 's':
1250 		*which = 1;	/* latitude */
1251 		break;
1252 	case 'E': case 'e':
1253 	case 'W': case 'w':
1254 		*which = 2;	/* longitude */
1255 		break;
1256 	default:
1257 		*which = 0;	/* error */
1258 		break;
1259 	}
1260 
1261 	cp++;			/* skip the hemisphere */
1262 
1263 	while (!isspace(*cp))	/* if any trailing garbage */
1264 		cp++;
1265 
1266 	while (isspace(*cp))	/* move to next field */
1267 		cp++;
1268 
1269 	*latlonstrptr = cp;
1270 
1271 	return (retval);
1272 }
1273 
1274 /* converts a zone file representation in a string to an RDATA on-the-wire
1275  * representation. */
1276 int
loc_aton(ascii,binary)1277 loc_aton(ascii, binary)
1278 	const char *ascii;
1279 	u_char *binary;
1280 {
1281 	const unsigned char *maxcp;
1282 	u_char *bcp;
1283 	unsigned char *cp;
1284 
1285 	u_int32_t latit = 0, longit = 0, alt = 0;
1286 	u_int32_t lltemp1 = 0, lltemp2 = 0;
1287 	int altmeters = 0, altfrac = 0, altsign = 1;
1288 	u_int8_t hp = 0x16;	/* default = 1e6 cm = 10000.00m = 10km */
1289 	u_int8_t vp = 0x13;	/* default = 1e3 cm = 10.00m */
1290 	u_int8_t siz = 0x12;	/* default = 1e2 cm = 1.00m */
1291 	int which1 = 0, which2 = 0;
1292 
1293 	cp = (unsigned char *)ascii;
1294 	maxcp = cp + strlen(ascii);
1295 
1296 	lltemp1 = latlon2ul(&cp, &which1);
1297 
1298 	lltemp2 = latlon2ul(&cp, &which2);
1299 
1300 	switch (which1 + which2) {
1301 	case 3:			/* 1 + 2, the only valid combination */
1302 		if ((which1 == 1) && (which2 == 2)) { /* normal case */
1303 			latit = lltemp1;
1304 			longit = lltemp2;
1305 		} else if ((which1 == 2) && (which2 == 1)) { /* reversed */
1306 			longit = lltemp1;
1307 			latit = lltemp2;
1308 		} else {	/* some kind of brokenness */
1309 			return (0);
1310 		}
1311 		break;
1312 	default:		/* we didn't get one of each */
1313 		return (0);
1314 	}
1315 
1316 	/* altitude */
1317 	if (*cp == '-') {
1318 		altsign = -1;
1319 		cp++;
1320 	}
1321 
1322 	if (*cp == '+')
1323 		cp++;
1324 
1325 	while (isdigit(*cp))
1326 		altmeters = altmeters * 10 + (*cp++ - '0');
1327 
1328 	if (*cp == '.') {		/* decimal meters */
1329 		cp++;
1330 		if (isdigit(*cp)) {
1331 			altfrac = (*cp++ - '0') * 10;
1332 			if (isdigit(*cp)) {
1333 				altfrac += (*cp++ - '0');
1334 			}
1335 		}
1336 	}
1337 
1338 	alt = (10000000 + (altsign * (altmeters * 100 + altfrac)));
1339 
1340 	while (!isspace(*cp) && (cp < maxcp)) /* if trailing garbage or m */
1341 		cp++;
1342 
1343 	while (isspace(*cp) && (cp < maxcp))
1344 		cp++;
1345 
1346 	if (cp >= maxcp)
1347 		goto defaults;
1348 
1349 	siz = precsize_aton(&cp);
1350 
1351 	while (!isspace(*cp) && (cp < maxcp))	/* if trailing garbage or m */
1352 		cp++;
1353 
1354 	while (isspace(*cp) && (cp < maxcp))
1355 		cp++;
1356 
1357 	if (cp >= maxcp)
1358 		goto defaults;
1359 
1360 	hp = precsize_aton(&cp);
1361 
1362 	while (!isspace(*cp) && (cp < maxcp))	/* if trailing garbage or m */
1363 		cp++;
1364 
1365 	while (isspace(*cp) && (cp < maxcp))
1366 		cp++;
1367 
1368 	if (cp >= maxcp)
1369 		goto defaults;
1370 
1371 	vp = precsize_aton(&cp);
1372 
1373  defaults:
1374 
1375 	bcp = binary;
1376 	*bcp++ = (u_int8_t) 0;	/* version byte */
1377 	*bcp++ = siz;
1378 	*bcp++ = hp;
1379 	*bcp++ = vp;
1380 	DNSRES_PUTLONG(latit,bcp);
1381 	DNSRES_PUTLONG(longit,bcp);
1382 	DNSRES_PUTLONG(alt,bcp);
1383 
1384 	return (16);		/* size of RR in octets */
1385 }
1386 
1387 const char *
loc_ntoa(binary,ascii)1388 loc_ntoa(binary, ascii)
1389 	const u_char *binary;
1390 	char *ascii;
1391 {
1392 	return loc_ntoal(binary, ascii, 255);
1393 }
1394 
1395 /* takes an on-the-wire LOC RR and formats it in a human readable format. */
1396 static const char *
loc_ntoal(binary,ascii,ascii_len)1397 loc_ntoal(binary, ascii, ascii_len)
1398 	const u_char *binary;
1399 	char *ascii;
1400 	int ascii_len;
1401 {
1402 	static char *error = "?";
1403 	register const u_char *cp = binary;
1404 
1405 	int latdeg, latmin, latsec, latsecfrac;
1406 	int longdeg, longmin, longsec, longsecfrac;
1407 	char northsouth, eastwest;
1408 	int altmeters, altfrac, altsign;
1409 
1410 	const int referencealt = 100000 * 100;
1411 
1412 	int32_t latval, longval, altval;
1413 	u_int32_t templ;
1414 	u_int8_t sizeval, hpval, vpval, versionval;
1415 
1416 	char *sizestr, *hpstr, *vpstr;
1417 
1418 	versionval = *cp++;
1419 
1420 	if (versionval) {
1421 		snprintf(ascii, ascii_len, "; error: unknown LOC RR version");
1422 		return (ascii);
1423 	}
1424 
1425 	sizeval = *cp++;
1426 
1427 	hpval = *cp++;
1428 	vpval = *cp++;
1429 
1430 	DNSRES_GETLONG(templ, cp);
1431 	latval = (templ - ((unsigned)1<<31));
1432 
1433 	DNSRES_GETLONG(templ, cp);
1434 	longval = (templ - ((unsigned)1<<31));
1435 
1436 	DNSRES_GETLONG(templ, cp);
1437 	if (templ < referencealt) { /* below WGS 84 spheroid */
1438 		altval = referencealt - templ;
1439 		altsign = -1;
1440 	} else {
1441 		altval = templ - referencealt;
1442 		altsign = 1;
1443 	}
1444 
1445 	if (latval < 0) {
1446 		northsouth = 'S';
1447 		latval = -latval;
1448 	} else
1449 		northsouth = 'N';
1450 
1451 	latsecfrac = latval % 1000;
1452 	latval = latval / 1000;
1453 	latsec = latval % 60;
1454 	latval = latval / 60;
1455 	latmin = latval % 60;
1456 	latval = latval / 60;
1457 	latdeg = latval;
1458 
1459 	if (longval < 0) {
1460 		eastwest = 'W';
1461 		longval = -longval;
1462 	} else
1463 		eastwest = 'E';
1464 
1465 	longsecfrac = longval % 1000;
1466 	longval = longval / 1000;
1467 	longsec = longval % 60;
1468 	longval = longval / 60;
1469 	longmin = longval % 60;
1470 	longval = longval / 60;
1471 	longdeg = longval;
1472 
1473 	altfrac = altval % 100;
1474 	altmeters = (altval / 100) * altsign;
1475 
1476 	if ((sizestr = strdup(precsize_ntoa(sizeval))) == NULL)
1477 		sizestr = error;
1478 	if ((hpstr = strdup(precsize_ntoa(hpval))) == NULL)
1479 		hpstr = error;
1480 	if ((vpstr = strdup(precsize_ntoa(vpval))) == NULL)
1481 		vpstr = error;
1482 
1483 	snprintf(ascii, ascii_len,
1484 	      "%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %d.%.2dm %sm %sm %sm",
1485 		latdeg, latmin, latsec, latsecfrac, northsouth,
1486 		longdeg, longmin, longsec, longsecfrac, eastwest,
1487 		altmeters, altfrac, sizestr, hpstr, vpstr);
1488 
1489 	if (sizestr != error)
1490 		free(sizestr);
1491 	if (hpstr != error)
1492 		free(hpstr);
1493 	if (vpstr != error)
1494 		free(vpstr);
1495 
1496 	return (ascii);
1497 }
1498 
1499 
1500 /* Return the number of DNS hierarchy levels in the name. */
1501 int
__dnsres_dn_count_labels(name)1502 __dnsres_dn_count_labels(name)
1503 	char *name;
1504 {
1505 	int i, len, count;
1506 
1507 	len = strlen(name);
1508 
1509 	for(i = 0, count = 0; i < len; i++) {
1510 		if (name[i] == '.')
1511 			count++;
1512 	}
1513 
1514 	/* don't count initial wildcard */
1515 	if (name[0] == '*')
1516 		if (count)
1517 			count--;
1518 
1519 	/* don't count the null label for root. */
1520 	/* if terminating '.' not found, must adjust */
1521 	/* count to include last label */
1522 	if (len > 0 && name[len-1] != '.')
1523 		count++;
1524 	return (count);
1525 }
1526 
1527 
1528 /*
1529  * Make dates expressed in seconds-since-Jan-1-1970 easy to read.
1530  * SIG records are required to be printed like this, by the Secure DNS RFC.
1531  */
1532 char *
__dnsres_p_secstodate(secs)1533 __dnsres_p_secstodate (secs)
1534 	unsigned long secs;
1535 {
1536 	static char output[15];		/* YYYYMMDDHHMMSS and null */
1537 	time_t clock = secs;
1538 	struct tm *time;
1539 
1540 	time = gmtime(&clock);
1541 	time->tm_year += 1900;
1542 	time->tm_mon += 1;
1543 	snprintf(output, sizeof output, "%04d%02d%02d%02d%02d%02d",
1544 		time->tm_year, time->tm_mon, time->tm_mday,
1545 		time->tm_hour, time->tm_min, time->tm_sec);
1546 	return (output);
1547 }
1548