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