Rewritten to use generic cache handling functions in cache.c.
[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 #undef p_query
242 /* ultrix 4.0's packaging has some icky packaging.  alias for it here.
243  * there is more junk of this kind over in res_comp.c.
244  */
245 void
246 p_query(msg)
247         const u_char *msg;
248 {
249         __p_query(msg);
250 }
251 #endif
252
253 /*
254  * Print the current options.
255  * This is intended to be primarily a debugging routine.
256  */
257 void
258 __fp_resstat(statp, file)
259         struct __res_state *statp;
260         FILE *file;
261 {
262         register u_long mask;
263
264         fprintf(file, ";; res options:");
265         if (!statp)
266                 statp = &_res;
267         for (mask = 1;  mask != 0;  mask <<= 1)
268                 if (statp->options & mask)
269                         fprintf(file, " %s", p_option(mask));
270         putc('\n', file);
271 }
272
273 /*
274  * Print the contents of a query.
275  * This is intended to be primarily a debugging routine.
276  */
277 void
278 __fp_nquery(msg, len, file)
279         const u_char *msg;
280         int len;
281         FILE *file;
282 {
283         register const u_char *cp, *endMark;
284         register const HEADER *hp;
285         register int n;
286
287         if ((_res.options & RES_INIT) == 0 && res_init() == -1)
288                 return;
289
290 #define TruncTest(x) if (x > endMark) goto trunc
291 #define ErrorTest(x) if (x == NULL) goto error
292
293         /*
294          * Print header fields.
295          */
296         hp = (HEADER *)msg;
297         cp = msg + HFIXEDSZ;
298         endMark = msg + len;
299         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX) || hp->rcode) {
300                 fprintf(file, ";; ->>HEADER<<- opcode: %s, status: %s, id: %d",
301                         _res_opcodes[hp->opcode],
302                         _res_resultcodes[hp->rcode],
303                         ntohs(hp->id));
304                 putc('\n', file);
305         }
306         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX))
307                 putc(';', file);
308         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD2)) {
309                 fprintf(file, "; flags:");
310                 if (hp->qr)
311                         fprintf(file, " qr");
312                 if (hp->aa)
313                         fprintf(file, " aa");
314                 if (hp->tc)
315                         fprintf(file, " tc");
316                 if (hp->rd)
317                         fprintf(file, " rd");
318                 if (hp->ra)
319                         fprintf(file, " ra");
320                 if (hp->unused)
321                         fprintf(file, " UNUSED-BIT-ON");
322                 if (hp->ad)
323                         fprintf(file, " ad");
324                 if (hp->cd)
325                         fprintf(file, " cd");
326         }
327         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD1)) {
328                 fprintf(file, "; Ques: %d", ntohs(hp->qdcount));
329                 fprintf(file, ", Ans: %d", ntohs(hp->ancount));
330                 fprintf(file, ", Auth: %d", ntohs(hp->nscount));
331                 fprintf(file, ", Addit: %d", ntohs(hp->arcount));
332         }
333         if ((!_res.pfcode) || (_res.pfcode &
334                 (RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) {
335                 putc('\n',file);
336         }
337         /*
338          * Print question records.
339          */
340         if ((n = ntohs(hp->qdcount))) {
341                 if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
342                         fprintf(file, ";; QUESTIONS:\n");
343                 while (--n >= 0) {
344                         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
345                                 fprintf(file, ";;\t");
346                         TruncTest(cp);
347                         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
348                                 cp = p_cdnname(cp, msg, len, file);
349                         else {
350                                 int n;
351                                 char name[MAXDNAME];
352
353                                 if ((n = dn_expand(msg, msg+len, cp, name,
354                                                 sizeof name)) < 0)
355                                         cp = NULL;
356                                 else
357                                         cp += n;
358                         }
359                         ErrorTest(cp);
360                         TruncTest(cp);
361                         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
362                                 fprintf(file, ", type = %s",
363                                         __p_type(_getshort((u_char*)cp)));
364                         cp += INT16SZ;
365                         TruncTest(cp);
366                         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
367                                 fprintf(file, ", class = %s\n",
368                                         __p_class(_getshort((u_char*)cp)));
369                         cp += INT16SZ;
370                         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
371                                 putc('\n', file);
372                 }
373         }
374         /*
375          * Print authoritative answer records
376          */
377         TruncTest(cp);
378         cp = do_rrset(msg, len, cp, hp->ancount, RES_PRF_ANS, file,
379                       ";; ANSWERS:\n");
380         ErrorTest(cp);
381
382         /*
383          * print name server records
384          */
385         TruncTest(cp);
386         cp = do_rrset(msg, len, cp, hp->nscount, RES_PRF_AUTH, file,
387                       ";; AUTHORITY RECORDS:\n");
388         ErrorTest(cp);
389
390         TruncTest(cp);
391         /*
392          * print additional records
393          */
394         cp = do_rrset(msg, len, cp, hp->arcount, RES_PRF_ADD, file,
395                       ";; ADDITIONAL RECORDS:\n");
396         ErrorTest(cp);
397         return;
398  trunc:
399         fprintf(file, "\n;; ...truncated\n");
400         return;
401  error:
402         fprintf(file, "\n;; ...malformed\n");
403 }
404
405 void
406 __fp_query(msg, file)
407         const u_char *msg;
408         FILE *file;
409 {
410         fp_nquery(msg, PACKETSZ, file);
411 }
412
413 const u_char *
414 __p_cdnname(cp, msg, len, file)
415         const u_char *cp, *msg;
416         int len;
417         FILE *file;
418 {
419         char name[MAXDNAME];
420         int n;
421
422         if ((n = dn_expand(msg, msg + len, cp, name, sizeof name)) < 0)
423                 return (NULL);
424         if (name[0] == '\0')
425                 putc('.', file);
426         else
427                 fputs(name, file);
428         return (cp + n);
429 }
430
431 const u_char *
432 __p_cdname(cp, msg, file)
433         const u_char *cp, *msg;
434         FILE *file;
435 {
436         return (p_cdnname(cp, msg, PACKETSZ, file));
437 }
438
439
440 /* Return a fully-qualified domain name from a compressed name (with
441    length supplied).  */
442
443 const u_char *
444 __p_fqnname(cp, msg, msglen, name, namelen)
445         const u_char *cp, *msg;
446         int msglen;
447         char *name;
448         int namelen;
449 {
450         int n, newlen;
451
452         if ((n = dn_expand(msg, cp + msglen, cp, name, namelen)) < 0)
453                 return (NULL);
454         newlen = strlen (name);
455         if (newlen == 0 || name[newlen - 1] != '.') {
456                 if (newlen+1 >= namelen)        /* Lack space for final dot */
457                         return (NULL);
458                 else
459                         strcpy(name + newlen, ".");
460         }
461         return (cp + n);
462 }
463
464 /* XXX: the rest of these functions need to become length-limited, too. (vix)
465  */
466
467 const u_char *
468 __p_fqname(cp, msg, file)
469         const u_char *cp, *msg;
470         FILE *file;
471 {
472         char name[MAXDNAME];
473         const u_char *n;
474
475         n = __p_fqnname(cp, msg, MAXCDNAME, name, sizeof name);
476         if (n == NULL)
477                 return (NULL);
478         fputs(name, file);
479         return (n);
480 }
481
482 /*
483  * Print resource record fields in human readable form.
484  */
485 const u_char *
486 __p_rr(cp, msg, file)
487         const u_char *cp, *msg;
488         FILE *file;
489 {
490         int type, class, dlen, n, c;
491         struct in_addr inaddr;
492         const u_char *cp1, *cp2;
493         u_int32_t tmpttl, t;
494         int lcnt;
495         u_int16_t keyflags;
496         char rrname[MAXDNAME];          /* The fqdn of this RR */
497         char base64_key[MAX_KEY_BASE64];
498
499         if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
500                 __set_h_errno (NETDB_INTERNAL);
501                 return (NULL);
502         }
503         cp = __p_fqnname(cp, msg, MAXCDNAME, rrname, sizeof rrname);
504         if (!cp)
505                 return (NULL);                  /* compression error */
506         fputs(rrname, file);
507
508         type = _getshort((u_char*)cp);
509         cp += INT16SZ;
510         class = _getshort((u_char*)cp);
511         cp += INT16SZ;
512         tmpttl = _getlong((u_char*)cp);
513         cp += INT32SZ;
514         dlen = _getshort((u_char*)cp);
515         cp += INT16SZ;
516         cp1 = cp;
517         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_TTLID))
518                 fprintf(file, "\t%lu", (u_long)tmpttl);
519         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_CLASS))
520                 fprintf(file, "\t%s", __p_class(class));
521         fprintf(file, "\t%s", __p_type(type));
522         /*
523          * Print type specific data, if appropriate
524          */
525         switch (type) {
526         case T_A:
527                 switch (class) {
528                 case C_IN:
529                 case C_HS:
530                         bcopy(cp, (char *)&inaddr, INADDRSZ);
531                         if (dlen == 4) {
532                                 fprintf(file, "\t%s", inet_ntoa(inaddr));
533                                 cp += dlen;
534                         } else if (dlen == 7) {
535                                 char *address;
536                                 u_char protocol;
537                                 u_short port;
538
539                                 address = inet_ntoa(inaddr);
540                                 cp += INADDRSZ;
541                                 protocol = *(u_char*)cp;
542                                 cp += sizeof (u_char);
543                                 port = _getshort((u_char*)cp);
544                                 cp += INT16SZ;
545                                 fprintf(file, "\t%s\t; proto %d, port %d",
546                                         address, protocol, port);
547                         }
548                         break;
549                 default:
550                         cp += dlen;
551                 }
552                 break;
553         case T_CNAME:
554         case T_MB:
555         case T_MG:
556         case T_MR:
557         case T_NS:
558         case T_PTR:
559                 putc('\t', file);
560                 if ((cp = p_fqname(cp, msg, file)) == NULL)
561                         return (NULL);
562                 break;
563
564         case T_HINFO:
565         case T_ISDN:
566                 cp2 = cp + dlen;
567                 (void) fputs("\t\"", file);
568                 if ((n = (unsigned char) *cp++) != 0) {
569                         for (c = n; c > 0 && cp < cp2; c--) {
570                                 if (strchr("\n\"\\", *cp))
571                                         (void) putc('\\', file);
572                                 (void) putc(*cp++, file);
573                         }
574                 }
575                 putc('"', file);
576                 if (cp < cp2 && (n = (unsigned char) *cp++) != 0) {
577                         (void) fputs ("\t\"", file);
578                         for (c = n; c > 0 && cp < cp2; c--) {
579                                 if (strchr("\n\"\\", *cp))
580                                         (void) putc('\\', file);
581                                 (void) putc(*cp++, file);
582                         }
583                         putc('"', file);
584                 } else if (type == T_HINFO) {
585                         (void) fputs("\"?\"", file);
586                         fprintf(file, "\n;; *** Warning *** OS-type missing");
587                 }
588                 break;
589
590         case T_SOA:
591                 putc('\t', file);
592                 if ((cp = p_fqname(cp, msg, file)) == NULL)
593                         return (NULL);
594                 putc(' ', file);
595                 if ((cp = p_fqname(cp, msg, file)) == NULL)
596                         return (NULL);
597                 fputs(" (\n", file);
598                 t = _getlong((u_char*)cp);  cp += INT32SZ;
599                 fprintf(file, "\t\t\t%lu\t; serial\n", (u_long)t);
600                 t = _getlong((u_char*)cp);  cp += INT32SZ;
601                 fprintf(file, "\t\t\t%lu\t; refresh (%s)\n",
602                         (u_long)t, __p_time(t));
603                 t = _getlong((u_char*)cp);  cp += INT32SZ;
604                 fprintf(file, "\t\t\t%lu\t; retry (%s)\n",
605                         (u_long)t, __p_time(t));
606                 t = _getlong((u_char*)cp);  cp += INT32SZ;
607                 fprintf(file, "\t\t\t%lu\t; expire (%s)\n",
608                         (u_long)t, __p_time(t));
609                 t = _getlong((u_char*)cp);  cp += INT32SZ;
610                 fprintf(file, "\t\t\t%lu )\t; minimum (%s)",
611                         (u_long)t, __p_time(t));
612                 break;
613
614         case T_MX:
615         case T_AFSDB:
616         case T_RT:
617                 fprintf(file, "\t%d ", _getshort((u_char*)cp));
618                 cp += INT16SZ;
619                 if ((cp = p_fqname(cp, msg, file)) == NULL)
620                         return (NULL);
621                 break;
622
623         case T_PX:
624                 fprintf(file, "\t%d ", _getshort((u_char*)cp));
625                 cp += INT16SZ;
626                 if ((cp = p_fqname(cp, msg, file)) == NULL)
627                         return (NULL);
628                 putc(' ', file);
629                 if ((cp = p_fqname(cp, msg, file)) == NULL)
630                         return (NULL);
631                 break;
632
633         case T_X25:
634                 cp2 = cp + dlen;
635                 (void) fputs("\t\"", file);
636                 if ((n = (unsigned char) *cp++) != 0) {
637                         for (c = n; c > 0 && cp < cp2; c--) {
638                                 if (strchr("\n\"\\", *cp))
639                                         (void) putc('\\', file);
640                                 (void) putc(*cp++, file);
641                         }
642                 }
643                 putc('"', file);
644                 break;
645
646         case T_TXT:
647                 (void) putc('\t', file);
648                 cp2 = cp1 + dlen;
649                 while (cp < cp2) {
650                         putc('"', file);
651                         if ((n = (unsigned char) *cp++)) {
652                                 for (c = n; c > 0 && cp < cp2; c--) {
653                                         if (strchr("\n\"\\", *cp))
654                                                 (void) putc('\\', file);
655                                         (void) putc(*cp++, file);
656                                 }
657                         }
658                         putc('"', file);
659                         if (cp < cp2)
660                                 putc(' ', file);
661                 }
662                 break;
663
664         case T_NSAP:
665                 (void) fprintf(file, "\t%s", inet_nsap_ntoa(dlen, cp, NULL));
666                 cp += dlen;
667                 break;
668
669         case T_AAAA: {
670                 char t[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
671
672                 fprintf(file, "\t%s", inet_ntop(AF_INET6, cp, t, sizeof t));
673                 cp += dlen;
674                 break;
675             }
676
677         case T_LOC: {
678                 char t[255];
679
680                 (void) fprintf(file, "\t%s", loc_ntoa(cp, t));
681                 cp += dlen;
682                 break;
683             }
684
685         case T_NAPTR: {
686                 u_int order, preference;
687
688                 order = _getshort(cp);  cp += INT16SZ;
689                 preference   = _getshort(cp);  cp += INT16SZ;
690                 fprintf(file, "\t%u %u ",order, preference);
691                 /* Flags */
692                 n = *cp++;
693                 fprintf(file,"\"%.*s\" ", (int)n, cp);
694                 cp += n;
695                 /* Service */
696                 n = *cp++;
697                 fprintf(file,"\"%.*s\" ", (int)n, cp);
698                 cp += n;
699                 /* Regexp */
700                 n = *cp++;
701                 fprintf(file,"\"%.*s\" ", (int)n, cp);
702                 cp += n;
703                 if ((cp = p_fqname(cp, msg, file)) == NULL)
704                         return (NULL);
705                 break;
706             }
707
708         case T_SRV: {
709                 u_int priority, weight, port;
710
711                 priority = _getshort(cp);  cp += INT16SZ;
712                 weight   = _getshort(cp);  cp += INT16SZ;
713                 port     = _getshort(cp);  cp += INT16SZ;
714                 fprintf(file, "\t%u %u %u ", priority, weight, port);
715                 if ((cp = p_fqname(cp, msg, file)) == NULL)
716                         return (NULL);
717                 break;
718             }
719
720         case T_MINFO:
721         case T_RP:
722                 putc('\t', file);
723                 if ((cp = p_fqname(cp, msg, file)) == NULL)
724                         return (NULL);
725                 putc(' ', file);
726                 if ((cp = p_fqname(cp, msg, file)) == NULL)
727                         return (NULL);
728                 break;
729
730         case T_UINFO:
731                 putc('\t', file);
732                 fputs((char *)cp, file);
733                 cp += dlen;
734                 break;
735
736         case T_UID:
737         case T_GID:
738                 if (dlen == 4) {
739                         fprintf(file, "\t%u", _getlong((u_char*)cp));
740                         cp += INT32SZ;
741                 }
742                 break;
743
744         case T_WKS:
745                 if (dlen < INT32SZ + 1)
746                         break;
747                 bcopy(cp, (char *)&inaddr, INADDRSZ);
748                 cp += INT32SZ;
749                 fprintf(file, "\t%s %s ( ",
750                         inet_ntoa(inaddr),
751                         deproto((int) *cp));
752                 cp += sizeof (u_char);
753                 n = 0;
754                 lcnt = 0;
755                 while (cp < cp1 + dlen) {
756                         c = *cp++;
757                         do {
758                                 if (c & 0200) {
759                                         if (lcnt == 0) {
760                                                 fputs("\n\t\t\t", file);
761                                                 lcnt = 5;
762                                         }
763                                         fputs(dewks(n), file);
764                                         putc(' ', file);
765                                         lcnt--;
766                                 }
767                                 c <<= 1;
768                         } while (++n & 07);
769                 }
770                 putc(')', file);
771                 break;
772
773         case T_KEY:
774                 putc('\t', file);
775                 keyflags = _getshort(cp);
776                 cp += 2;
777                 fprintf(file,"0x%04x", keyflags );      /* flags */
778                 fprintf(file," %u", *cp++);     /* protocol */
779                 fprintf(file," %u (", *cp++);   /* algorithm */
780
781                 n = b64_ntop(cp, (cp1 + dlen) - cp,
782                              base64_key, sizeof base64_key);
783                 for (c = 0; c < n; ++c) {
784                         if (0 == (c & 0x3F))
785                                 fprintf(file, "\n\t");
786                         putc(base64_key[c], file);  /* public key data */
787                 }
788
789                 fprintf(file, " )");
790                 if (n < 0)
791                         fprintf(file, "\t; BAD BASE64");
792                 fflush(file);
793                 cp = cp1 + dlen;
794                 break;
795
796         case T_SIG:
797                 type = _getshort((u_char*)cp);
798                 cp += INT16SZ;
799                 fprintf(file, " %s", p_type(type));
800                 fprintf(file, "\t%d", *cp++);   /* algorithm */
801                 /* Check label value and print error if wrong. */
802                 n = *cp++;
803                 c = dn_count_labels (rrname);
804                 if (n != c)
805                         fprintf(file, "\t; LABELS WRONG (%d should be %d)\n\t",
806                                 n, c);
807                 /* orig ttl */
808                 n = _getlong((u_char*)cp);
809                 if ((u_int32_t) n != tmpttl)
810                         fprintf(file, " %u", n);
811                 cp += INT32SZ;
812                 /* sig expire */
813                 fprintf(file, " (\n\t%s",
814                         __p_secstodate(_getlong((u_char*)cp)));
815                 cp += INT32SZ;
816                 /* time signed */
817                 fprintf(file, " %s", __p_secstodate(_getlong((u_char*)cp)));
818                 cp += INT32SZ;
819                 /* sig footprint */
820                 fprintf(file," %u ", _getshort((u_char*)cp));
821                 cp += INT16SZ;
822                 /* signer's name */
823                 cp = p_fqname(cp, msg, file);
824                 n = b64_ntop(cp, (cp1 + dlen) - cp,
825                              base64_key, sizeof base64_key);
826                 for (c = 0; c < n; c++) {
827                         if (0 == (c & 0x3F))
828                                 fprintf (file, "\n\t");
829                         putc(base64_key[c], file);              /* signature */
830                 }
831                 /* Clean up... */
832                 fprintf(file, " )");
833                 if (n < 0)
834                         fprintf(file, "\t; BAD BASE64");
835                 fflush(file);
836                 cp = cp1+dlen;
837                 break;
838
839 #ifdef ALLOW_T_UNSPEC
840         case T_UNSPEC:
841                 {
842                         int NumBytes = 8;
843                         u_char *DataPtr;
844                         int i;
845
846                         if (dlen < NumBytes) NumBytes = dlen;
847                         fprintf(file, "\tFirst %d bytes of hex data:",
848                                 NumBytes);
849                         for (i = 0, DataPtr = cp; i < NumBytes; i++, DataPtr++)
850                                 fprintf(file, " %x", *DataPtr);
851                         cp += dlen;
852                 }
853                 break;
854 #endif /* ALLOW_T_UNSPEC */
855
856         default:
857                 fprintf(file, "\t?%d?", type);
858                 cp += dlen;
859         }
860 #if 0
861         fprintf(file, "\t; dlen=%d, ttl %s\n", dlen, __p_time(tmpttl));
862 #else
863         putc('\n', file);
864 #endif
865         if (cp - cp1 != dlen) {
866                 fprintf(file,
867                         ";; packet size error (found %lu, dlen was %d)\n",
868                         (unsigned long) (cp - cp1), dlen);
869                 cp = NULL;
870         }
871         return (cp);
872 }
873
874 /*
875  * Names of RR classes and qclasses.  Classes and qclasses are the same, except
876  * that C_ANY is a qclass but not a class.  (You can ask for records of class
877  * C_ANY, but you can't have any records of that class in the database.)
878  */
879 const struct res_sym __p_class_syms[] = {
880         {C_IN,          "IN"},
881         {C_CHAOS,       "CHAOS"},
882         {C_HS,          "HS"},
883         {C_HS,          "HESIOD"},
884         {C_ANY,         "ANY"},
885         {C_IN,          (char *)0}
886 };
887
888 /*
889  * Names of RR types and qtypes.  Types and qtypes are the same, except
890  * that T_ANY is a qtype but not a type.  (You can ask for records of type
891  * T_ANY, but you can't have any records of that type in the database.)
892  */
893 const struct res_sym __p_type_syms[] = {
894         {T_A,           "A",            "address"},
895         {T_NS,          "NS",           "name server"},
896         {T_MD,          "MD",           "mail destination (deprecated)"},
897         {T_MF,          "MF",           "mail forwarder (deprecated)"},
898         {T_CNAME,       "CNAME",        "canonical name"},
899         {T_SOA,         "SOA",          "start of authority"},
900         {T_MB,          "MB",           "mailbox"},
901         {T_MG,          "MG",           "mail group member"},
902         {T_MR,          "MR",           "mail rename"},
903         {T_NULL,        "NULL",         "null"},
904         {T_WKS,         "WKS",          "well-known service (deprecated)"},
905         {T_PTR,         "PTR",          "domain name pointer"},
906         {T_HINFO,       "HINFO",        "host information"},
907         {T_MINFO,       "MINFO",        "mailbox information"},
908         {T_MX,          "MX",           "mail exchanger"},
909         {T_TXT,         "TXT",          "text"},
910         {T_RP,          "RP",           "responsible person"},
911         {T_AFSDB,       "AFSDB",        "DCE or AFS server"},
912         {T_X25,         "X25",          "X25 address"},
913         {T_ISDN,        "ISDN",         "ISDN address"},
914         {T_RT,          "RT",           "router"},
915         {T_NSAP,        "NSAP",         "nsap address"},
916         {T_NSAP_PTR,    "NSAP_PTR",     "domain name pointer"},
917         {T_SIG,         "SIG",          "signature"},
918         {T_KEY,         "KEY",          "key"},
919         {T_PX,          "PX",           "mapping information"},
920         {T_GPOS,        "GPOS",         "geographical position (withdrawn)"},
921         {T_AAAA,        "AAAA",         "IPv6 address"},
922         {T_LOC,         "LOC",          "location"},
923         {T_NXT,         "NXT",          "next valid name (unimplemented)"},
924         {T_EID,         "EID",          "endpoint identifier (unimplemented)"},
925         {T_NIMLOC,      "NIMLOC",       "NIMROD locator (unimplemented)"},
926         {T_SRV,         "SRV",          "server selection"},
927         {T_ATMA,        "ATMA",         "ATM address (unimplemented)"},
928         {T_IXFR,        "IXFR",         "incremental zone transfer"},
929         {T_AXFR,        "AXFR",         "zone transfer"},
930         {T_MAILB,       "MAILB",        "mailbox-related data (deprecated)"},
931         {T_MAILA,       "MAILA",        "mail agent (deprecated)"},
932         {T_UINFO,       "UINFO",        "user information (nonstandard)"},
933         {T_UID,         "UID",          "user ID (nonstandard)"},
934         {T_GID,         "GID",          "group ID (nonstandard)"},
935         {T_NAPTR,       "NAPTR",        "URN Naming Authority"},
936 #ifdef ALLOW_T_UNSPEC
937         {T_UNSPEC,      "UNSPEC",       "unspecified data (nonstandard)"},
938 #endif /* ALLOW_T_UNSPEC */
939         {T_ANY,         "ANY",          "\"any\""},
940         {0,             NULL,           NULL}
941 };
942
943 int
944 __sym_ston(syms, name, success)
945         const struct res_sym *syms;
946         char *name;
947         int *success;
948 {
949 #ifdef _LIBC
950         /* Changed to prevent warning. --drepper@gnu  */
951         for (; syms->name != 0; syms++) {
952 #else
953         for (NULL; syms->name != 0; syms++) {
954 #endif
955                 if (strcasecmp (name, syms->name) == 0) {
956                         if (success)
957                                 *success = 1;
958                         return (syms->number);
959                 }
960         }
961         if (success)
962                 *success = 0;
963         return (syms->number);          /* The default value. */
964 }
965
966 const char *
967 __sym_ntos(syms, number, success)
968         const struct res_sym *syms;
969         int number;
970         int *success;
971 {
972         static char unname[20];
973
974 #ifdef _LIBC
975         /* Changed to prevent warning. --drepper@gnu  */
976         for (; syms->name != 0; syms++) {
977 #else
978         for (NULL; syms->name != 0; syms++) {
979 #endif
980                 if (number == syms->number) {
981                         if (success)
982                                 *success = 1;
983                         return (syms->name);
984                 }
985         }
986
987         sprintf (unname, "%d", number);
988         if (success)
989                 *success = 0;
990         return (unname);
991 }
992
993
994 const char *
995 __sym_ntop(syms, number, success)
996         const struct res_sym *syms;
997         int number;
998         int *success;
999 {
1000         static char unname[20];
1001
1002 #ifdef _LIBC
1003         /* Changed to prevent warning. --drepper@gnu  */
1004         for (; syms->name != 0; syms++) {
1005 #else
1006         for (NULL; syms->name != 0; syms++) {
1007 #endif
1008                 if (number == syms->number) {
1009                         if (success)
1010                                 *success = 1;
1011                         return (syms->humanname);
1012                 }
1013         }
1014         sprintf(unname, "%d", number);
1015         if (success)
1016                 *success = 0;
1017         return (unname);
1018 }
1019
1020 /*
1021  * Return a string for the type
1022  */
1023 const char *
1024 __p_type(type)
1025         int type;
1026 {
1027         return (__sym_ntos (__p_type_syms, type, (int *)0));
1028 }
1029
1030 /*
1031  * Return a mnemonic for class
1032  */
1033 const char *
1034 __p_class(class)
1035         int class;
1036 {
1037         return (__sym_ntos (__p_class_syms, class, (int *)0));
1038 }
1039
1040 /*
1041  * Return a mnemonic for an option
1042  */
1043 const char *
1044 __p_option(option)
1045         u_long option;
1046 {
1047         static char nbuf[40];
1048
1049         switch (option) {
1050         case RES_INIT:          return "init";
1051         case RES_DEBUG:         return "debug";
1052         case RES_AAONLY:        return "aaonly(unimpl)";
1053         case RES_USEVC:         return "usevc";
1054         case RES_PRIMARY:       return "primry(unimpl)";
1055         case RES_IGNTC:         return "igntc";
1056         case RES_RECURSE:       return "recurs";
1057         case RES_DEFNAMES:      return "defnam";
1058         case RES_STAYOPEN:      return "styopn";
1059         case RES_DNSRCH:        return "dnsrch";
1060         case RES_INSECURE1:     return "insecure1";
1061         case RES_INSECURE2:     return "insecure2";
1062         default:                sprintf(nbuf, "?0x%lx?", (u_long)option);
1063                                 return (nbuf);
1064         }
1065 }
1066
1067 /*
1068  * Return a mnemonic for a time to live
1069  */
1070 const char *
1071 p_time(value)
1072         u_int32_t value;
1073 {
1074         static char nbuf[60];
1075         int secs, mins, hours, days;
1076         register char *p;
1077
1078         if (value == 0) {
1079                 strcpy(nbuf, "0 secs");
1080                 return (nbuf);
1081         }
1082
1083         secs = value % 60;
1084         value /= 60;
1085         mins = value % 60;
1086         value /= 60;
1087         hours = value % 24;
1088         value /= 24;
1089         days = value;
1090         value = 0;
1091
1092 #define PLURALIZE(x)    x, (x == 1) ? "" : "s"
1093         p = nbuf;
1094         if (days) {
1095                 (void)sprintf(p, "%d day%s", PLURALIZE(days));
1096                 while (*++p);
1097         }
1098         if (hours) {
1099                 if (days)
1100                         *p++ = ' ';
1101                 (void)sprintf(p, "%d hour%s", PLURALIZE(hours));
1102                 while (*++p);
1103         }
1104         if (mins) {
1105                 if (days || hours)
1106                         *p++ = ' ';
1107                 (void)sprintf(p, "%d min%s", PLURALIZE(mins));
1108                 while (*++p);
1109         }
1110         if (secs || ! (days || hours || mins)) {
1111                 if (days || hours || mins)
1112                         *p++ = ' ';
1113                 (void)sprintf(p, "%d sec%s", PLURALIZE(secs));
1114         }
1115         return (nbuf);
1116 }
1117
1118 /*
1119  * routines to convert between on-the-wire RR format and zone file format.
1120  * Does not contain conversion to/from decimal degrees; divide or multiply
1121  * by 60*60*1000 for that.
1122  */
1123
1124 static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
1125                                       1000000,10000000,100000000,1000000000};
1126
1127 /* takes an XeY precision/size value, returns a string representation. */
1128 static const char *
1129 precsize_ntoa(prec)
1130         u_int8_t prec;
1131 {
1132         static char retbuf[sizeof "90000000.00"];
1133         unsigned long val;
1134         int mantissa, exponent;
1135
1136         mantissa = (int)((prec >> 4) & 0x0f) % 10;
1137         exponent = (int)((prec >> 0) & 0x0f) % 10;
1138
1139         val = mantissa * poweroften[exponent];
1140
1141         (void) sprintf(retbuf, "%ld.%.2ld", val/100, val%100);
1142         return (retbuf);
1143 }
1144
1145 /* converts ascii size/precision X * 10**Y(cm) to 0xXY.  moves pointer. */
1146 static u_int8_t
1147 precsize_aton(strptr)
1148         char **strptr;
1149 {
1150         u_int8_t retval = 0;
1151         char *cp;
1152         int exponent = 0;
1153         int mantissa = 0;
1154
1155         cp = *strptr;
1156         while (isdigit(*cp)) {
1157                 if (mantissa == 0)
1158                         mantissa = *cp - '0';
1159                 else
1160                         exponent++;
1161                 cp++;
1162         }
1163
1164         if (*cp == '.') {
1165                 cp++;
1166                 if (isdigit(*cp)) {
1167                         if (mantissa == 0)
1168                                 mantissa = *cp - '0';
1169                         else
1170                                 exponent++;
1171                         cp++;
1172
1173                         if (isdigit(*cp)) {
1174                                 if (mantissa == 0)
1175                                         mantissa = *cp - '0';
1176                                 else
1177                                         exponent++;
1178                                 cp++;
1179                         }
1180                         else
1181                                 exponent++;
1182                 }
1183         }
1184         else
1185                 exponent += 2;
1186
1187         if (mantissa == 0)
1188                 exponent = 0;
1189         retval = (mantissa << 4) | exponent;
1190         *strptr = cp;
1191         return (retval);
1192 }
1193
1194 /* converts ascii lat/lon to unsigned encoded 32-bit number.  moves pointer. */
1195 static u_int32_t
1196 latlon2ul(latlonstrptr,which)
1197         char **latlonstrptr;
1198         int *which;
1199 {
1200         register char *cp;
1201         u_int32_t retval;
1202         int deg = 0, min = 0, secs = 0, secsfrac = 0;
1203
1204         cp = *latlonstrptr;
1205
1206         while (isdigit(*cp))
1207                 deg = deg * 10 + (*cp++ - '0');
1208
1209         while (isspace(*cp))
1210                 cp++;
1211
1212         if (!(isdigit(*cp)))
1213                 goto fndhemi;
1214
1215         while (isdigit(*cp))
1216                 min = min * 10 + (*cp++ - '0');
1217
1218         while (isspace(*cp))
1219                 cp++;
1220
1221         if (!(isdigit(*cp)))
1222                 goto fndhemi;
1223
1224         while (isdigit(*cp))
1225                 secs = secs * 10 + (*cp++ - '0');
1226
1227         if (*cp == '.') {               /* decimal seconds */
1228                 cp++;
1229                 if (isdigit(*cp)) {
1230                         secsfrac = (*cp++ - '0') * 100;
1231                         if (isdigit(*cp)) {
1232                                 secsfrac += (*cp++ - '0') * 10;
1233                                 if (isdigit(*cp)) {
1234                                         secsfrac += (*cp++ - '0');
1235                                 }
1236                         }
1237                 }
1238         }
1239
1240         while (!isspace(*cp))   /* if any trailing garbage */
1241                 cp++;
1242
1243         while (isspace(*cp))
1244                 cp++;
1245
1246  fndhemi:
1247         switch (*cp) {
1248         case 'N': case 'n':
1249         case 'E': case 'e':
1250                 retval = ((unsigned)1<<31)
1251                         + (((((deg * 60) + min) * 60) + secs) * 1000)
1252                         + secsfrac;
1253                 break;
1254         case 'S': case 's':
1255         case 'W': case 'w':
1256                 retval = ((unsigned)1<<31)
1257                         - (((((deg * 60) + min) * 60) + secs) * 1000)
1258                         - secsfrac;
1259                 break;
1260         default:
1261                 retval = 0;     /* invalid value -- indicates error */
1262                 break;
1263         }
1264
1265         switch (*cp) {
1266         case 'N': case 'n':
1267         case 'S': case 's':
1268                 *which = 1;     /* latitude */
1269                 break;
1270         case 'E': case 'e':
1271         case 'W': case 'w':
1272                 *which = 2;     /* longitude */
1273                 break;
1274         default:
1275                 *which = 0;     /* error */
1276                 break;
1277         }
1278
1279         cp++;                   /* skip the hemisphere */
1280
1281         while (!isspace(*cp))   /* if any trailing garbage */
1282                 cp++;
1283
1284         while (isspace(*cp))    /* move to next field */
1285                 cp++;
1286
1287         *latlonstrptr = cp;
1288
1289         return (retval);
1290 }
1291
1292 /* converts a zone file representation in a string to an RDATA on-the-wire
1293  * representation. */
1294 int
1295 loc_aton(ascii, binary)
1296         const char *ascii;
1297         u_char *binary;
1298 {
1299         const char *cp, *maxcp;
1300         u_char *bcp;
1301
1302         u_int32_t latit = 0, longit = 0, alt = 0;
1303         u_int32_t lltemp1 = 0, lltemp2 = 0;
1304         int altmeters = 0, altfrac = 0, altsign = 1;
1305         u_int8_t hp = 0x16;     /* default = 1e6 cm = 10000.00m = 10km */
1306         u_int8_t vp = 0x13;     /* default = 1e3 cm = 10.00m */
1307         u_int8_t siz = 0x12;    /* default = 1e2 cm = 1.00m */
1308         int which1 = 0, which2 = 0;
1309
1310         cp = ascii;
1311         maxcp = cp + strlen(ascii);
1312
1313         lltemp1 = latlon2ul(&cp, &which1);
1314
1315         lltemp2 = latlon2ul(&cp, &which2);
1316
1317         switch (which1 + which2) {
1318         case 3:                 /* 1 + 2, the only valid combination */
1319                 if ((which1 == 1) && (which2 == 2)) { /* normal case */
1320                         latit = lltemp1;
1321                         longit = lltemp2;
1322                 } else if ((which1 == 2) && (which2 == 1)) { /* reversed */
1323                         longit = lltemp1;
1324                         latit = lltemp2;
1325                 } else {        /* some kind of brokenness */
1326                         return (0);
1327                 }
1328                 break;
1329         default:                /* we didn't get one of each */
1330                 return (0);
1331         }
1332
1333         /* altitude */
1334         if (*cp == '-') {
1335                 altsign = -1;
1336                 cp++;
1337         }
1338
1339         if (*cp == '+')
1340                 cp++;
1341
1342         while (isdigit(*cp))
1343                 altmeters = altmeters * 10 + (*cp++ - '0');
1344
1345         if (*cp == '.') {               /* decimal meters */
1346                 cp++;
1347                 if (isdigit(*cp)) {
1348                         altfrac = (*cp++ - '0') * 10;
1349                         if (isdigit(*cp)) {
1350                                 altfrac += (*cp++ - '0');
1351                         }
1352                 }
1353         }
1354
1355         alt = (10000000 + (altsign * (altmeters * 100 + altfrac)));
1356
1357         while (!isspace(*cp) && (cp < maxcp)) /* if trailing garbage or m */
1358                 cp++;
1359
1360         while (isspace(*cp) && (cp < maxcp))
1361                 cp++;
1362
1363         if (cp >= maxcp)
1364                 goto defaults;
1365
1366         siz = precsize_aton(&cp);
1367
1368         while (!isspace(*cp) && (cp < maxcp))   /* if trailing garbage or m */
1369                 cp++;
1370
1371         while (isspace(*cp) && (cp < maxcp))
1372                 cp++;
1373
1374         if (cp >= maxcp)
1375                 goto defaults;
1376
1377         hp = precsize_aton(&cp);
1378
1379         while (!isspace(*cp) && (cp < maxcp))   /* if trailing garbage or m */
1380                 cp++;
1381
1382         while (isspace(*cp) && (cp < maxcp))
1383                 cp++;
1384
1385         if (cp >= maxcp)
1386                 goto defaults;
1387
1388         vp = precsize_aton(&cp);
1389
1390  defaults:
1391
1392         bcp = binary;
1393         *bcp++ = (u_int8_t) 0;  /* version byte */
1394         *bcp++ = siz;
1395         *bcp++ = hp;
1396         *bcp++ = vp;
1397         PUTLONG(latit,bcp);
1398         PUTLONG(longit,bcp);
1399         PUTLONG(alt,bcp);
1400
1401         return (16);            /* size of RR in octets */
1402 }
1403
1404 /* takes an on-the-wire LOC RR and formats it in a human readable format. */
1405 const char *
1406 loc_ntoa(binary, ascii)
1407         const u_char *binary;
1408         char *ascii;
1409 {
1410         static char *error = "?";
1411         register const u_char *cp = binary;
1412
1413         int latdeg, latmin, latsec, latsecfrac;
1414         int longdeg, longmin, longsec, longsecfrac;
1415         char northsouth, eastwest;
1416         int altmeters, altfrac, altsign;
1417
1418         const int referencealt = 100000 * 100;
1419
1420         int32_t latval, longval, altval;
1421         u_int32_t templ;
1422         u_int8_t sizeval, hpval, vpval, versionval;
1423
1424         char *sizestr, *hpstr, *vpstr;
1425
1426         versionval = *cp++;
1427
1428         if (versionval) {
1429                 sprintf(ascii, "; error: unknown LOC RR version");
1430                 return (ascii);
1431         }
1432
1433         sizeval = *cp++;
1434
1435         hpval = *cp++;
1436         vpval = *cp++;
1437
1438         GETLONG(templ, cp);
1439         latval = (templ - ((unsigned)1<<31));
1440
1441         GETLONG(templ, cp);
1442         longval = (templ - ((unsigned)1<<31));
1443
1444         GETLONG(templ, cp);
1445         if (templ < (u_int32_t) referencealt) { /* below WGS 84 spheroid */
1446                 altval = referencealt - templ;
1447                 altsign = -1;
1448         } else {
1449                 altval = templ - referencealt;
1450                 altsign = 1;
1451         }
1452
1453         if (latval < 0) {
1454                 northsouth = 'S';
1455                 latval = -latval;
1456         } else
1457                 northsouth = 'N';
1458
1459         latsecfrac = latval % 1000;
1460         latval = latval / 1000;
1461         latsec = latval % 60;
1462         latval = latval / 60;
1463         latmin = latval % 60;
1464         latval = latval / 60;
1465         latdeg = latval;
1466
1467         if (longval < 0) {
1468                 eastwest = 'W';
1469                 longval = -longval;
1470         } else
1471                 eastwest = 'E';
1472
1473         longsecfrac = longval % 1000;
1474         longval = longval / 1000;
1475         longsec = longval % 60;
1476         longval = longval / 60;
1477         longmin = longval % 60;
1478         longval = longval / 60;
1479         longdeg = longval;
1480
1481         altfrac = altval % 100;
1482         altmeters = (altval / 100) * altsign;
1483
1484         if ((sizestr = strdup(precsize_ntoa(sizeval))) == NULL)
1485                 sizestr = error;
1486         if ((hpstr = strdup(precsize_ntoa(hpval))) == NULL)
1487                 hpstr = error;
1488         if ((vpstr = strdup(precsize_ntoa(vpval))) == NULL)
1489                 vpstr = error;
1490
1491         sprintf(ascii,
1492               "%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %d.%.2dm %sm %sm %sm",
1493                 latdeg, latmin, latsec, latsecfrac, northsouth,
1494                 longdeg, longmin, longsec, longsecfrac, eastwest,
1495                 altmeters, altfrac, sizestr, hpstr, vpstr);
1496
1497         if (sizestr != error)
1498                 free(sizestr);
1499         if (hpstr != error)
1500                 free(hpstr);
1501         if (vpstr != error)
1502                 free(vpstr);
1503
1504         return (ascii);
1505 }
1506
1507
1508 /* Return the number of DNS hierarchy levels in the name. */
1509 int
1510 __dn_count_labels(name)
1511         char *name;
1512 {
1513         int i, len, count;
1514
1515         len = strlen(name);
1516
1517         for(i = 0, count = 0; i < len; i++) {
1518                 if (name[i] == '.')
1519                         count++;
1520         }
1521
1522         /* don't count initial wildcard */
1523         if (name[0] == '*')
1524                 if (count)
1525                         count--;
1526
1527         /* don't count the null label for root. */
1528         /* if terminating '.' not found, must adjust */
1529         /* count to include last label */
1530         if (len > 0 && name[len-1] != '.')
1531                 count++;
1532         return (count);
1533 }
1534
1535
1536 /*
1537  * Make dates expressed in seconds-since-Jan-1-1970 easy to read.
1538  * SIG records are required to be printed like this, by the Secure DNS RFC.
1539  */
1540 char *
1541 __p_secstodate (secs)
1542         unsigned long secs;
1543 {
1544         static char output[15];         /* YYYYMMDDHHMMSS and null */
1545         time_t clock = secs;
1546         struct tm time;
1547
1548         __gmtime_r(&clock, &time);
1549         time.tm_year += 1900;
1550         time.tm_mon += 1;
1551         sprintf(output, "%04d%02d%02d%02d%02d%02d",
1552                 time.tm_year, time.tm_mon, time.tm_mday,
1553                 time.tm_hour, time.tm_min, time.tm_sec);
1554         return (output);
1555 }