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