c2fefb47506c25f9ad039f0b14ed26e6c47d91ed
[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  * --Copyright--
54  */
55
56 #if defined(LIBC_SCCS) && !defined(lint)
57 static char sccsid[] = "@(#)res_debug.c 8.1 (Berkeley) 6/4/93";
58 static char rcsid[] = "$Id$";
59 #endif /* LIBC_SCCS and not lint */
60
61 #include <sys/param.h>
62 #include <sys/types.h>
63 #include <sys/socket.h>
64 #include <netinet/in.h>
65 #include <arpa/inet.h>
66 #include <arpa/nameser.h>
67
68 #include <stdio.h>
69 #include <netdb.h>
70 #include <resolv.h>
71 #if defined(BSD) && (BSD >= 199103) && defined(AF_INET6)
72 # include <string.h>
73 #else
74 # include "../conf/portability.h"
75 #endif
76
77 #if defined(USE_OPTIONS_H)
78 # include "../conf/options.h"
79 #endif
80
81 extern const char *_res_opcodes[];
82 extern const char *_res_resultcodes[];
83
84 /* XXX: we should use getservbyport() instead. */
85 static const char *
86 dewks(wks)
87         int wks;
88 {
89         static char nbuf[20];
90
91         switch (wks) {
92         case 5: return "rje";
93         case 7: return "echo";
94         case 9: return "discard";
95         case 11: return "systat";
96         case 13: return "daytime";
97         case 15: return "netstat";
98         case 17: return "qotd";
99         case 19: return "chargen";
100         case 20: return "ftp-data";
101         case 21: return "ftp";
102         case 23: return "telnet";
103         case 25: return "smtp";
104         case 37: return "time";
105         case 39: return "rlp";
106         case 42: return "name";
107         case 43: return "whois";
108         case 53: return "domain";
109         case 57: return "apts";
110         case 59: return "apfs";
111         case 67: return "bootps";
112         case 68: return "bootpc";
113         case 69: return "tftp";
114         case 77: return "rje";
115         case 79: return "finger";
116         case 87: return "link";
117         case 95: return "supdup";
118         case 100: return "newacct";
119         case 101: return "hostnames";
120         case 102: return "iso-tsap";
121         case 103: return "x400";
122         case 104: return "x400-snd";
123         case 105: return "csnet-ns";
124         case 109: return "pop-2";
125         case 111: return "sunrpc";
126         case 113: return "auth";
127         case 115: return "sftp";
128         case 117: return "uucp-path";
129         case 119: return "nntp";
130         case 121: return "erpc";
131         case 123: return "ntp";
132         case 133: return "statsrv";
133         case 136: return "profile";
134         case 144: return "NeWS";
135         case 161: return "snmp";
136         case 162: return "snmp-trap";
137         case 170: return "print-srv";
138         default: (void) sprintf(nbuf, "%d", wks); return (nbuf);
139         }
140 }
141
142 /* XXX: we should use getprotobynumber() instead. */
143 static const char *
144 deproto(protonum)
145         int protonum;
146 {
147         static char nbuf[20];
148
149         switch (protonum) {
150         case 1: return "icmp";
151         case 2: return "igmp";
152         case 3: return "ggp";
153         case 5: return "st";
154         case 6: return "tcp";
155         case 7: return "ucl";
156         case 8: return "egp";
157         case 9: return "igp";
158         case 11: return "nvp-II";
159         case 12: return "pup";
160         case 16: return "chaos";
161         case 17: return "udp";
162         default: (void) sprintf(nbuf, "%d", protonum); return (nbuf);
163         }
164 }
165
166 static const u_char *
167 do_rrset(msg, len, cp, cnt, pflag, file, hs)
168         int cnt, pflag, len;
169         const u_char *cp, *msg;
170         const char *hs;
171         FILE *file;
172 {
173         int n;
174         int sflag;
175
176         /*
177          * Print answer records.
178          */
179         sflag = (_res.pfcode & pflag);
180         if (n = ntohs(cnt)) {
181                 if ((!_res.pfcode) ||
182                     ((sflag) && (_res.pfcode & RES_PRF_HEAD1)))
183                         fprintf(file, hs);
184                 while (--n >= 0) {
185                         if ((!_res.pfcode) || sflag) {
186                                 cp = p_rr(cp, msg, file);
187                         } else {
188                                 unsigned int dlen;
189                                 cp += __dn_skipname(cp, cp + MAXCDNAME);
190                                 cp += INT16SZ;
191                                 cp += INT16SZ;
192                                 cp += INT32SZ;
193                                 dlen = _getshort((u_char*)cp);
194                                 cp += INT16SZ;
195                                 cp += dlen;
196                         }
197                         if ((cp - msg) > len)
198                                 return (NULL);
199                 }
200                 if ((!_res.pfcode) ||
201                     ((sflag) && (_res.pfcode & RES_PRF_HEAD1)))
202                         putc('\n', file);
203         }
204         return (cp);
205 }
206
207 void
208 __p_query(msg)
209         const u_char *msg;
210 {
211         __fp_query(msg, stdout);
212 }
213
214 #ifdef ultrix
215 /* ultrix 4.0's packaging has some icky packaging.  alias for it here.
216  * there is more junk of this kind over in res_comp.c.
217  */
218 void
219 p_query(msg)
220         const u_char *msg;
221 {
222         __p_query(msg);
223 }
224 #endif
225
226 /*
227  * Print the current options.
228  * This is intended to be primarily a debugging routine.
229  */
230 void
231 __fp_resstat(statp, file)
232         struct __res_state *statp;
233         FILE *file;
234 {
235         register u_long mask;
236
237         fprintf(file, ";; res options:");
238         if (!statp)
239                 statp = &_res;
240         for (mask = 1;  mask != 0;  mask <<= 1)
241                 if (statp->options & mask)
242                         fprintf(file, " %s", p_option(mask));
243         putc('\n', file);
244 }
245
246 /*
247  * Print the contents of a query.
248  * This is intended to be primarily a debugging routine.
249  */
250 void
251 __fp_nquery(msg, len, file)
252         const u_char *msg;
253         int len;
254         FILE *file;
255 {
256         register const u_char *cp, *endMark;
257         register const HEADER *hp;
258         register int n;
259
260         if ((_res.options & RES_INIT) == 0 && res_init() == -1)
261                 return;
262
263 #define TruncTest(x) if (x >= endMark) goto trunc
264 #define ErrorTest(x) if (x == NULL) goto error
265
266         /*
267          * Print header fields.
268          */
269         hp = (HEADER *)msg;
270         cp = msg + HFIXEDSZ;
271         endMark = cp + len;
272         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX) || hp->rcode) {
273                 fprintf(file, ";; ->>HEADER<<- opcode: %s, status: %s, id: %d",
274                         _res_opcodes[hp->opcode],
275                         _res_resultcodes[hp->rcode],
276                         ntohs(hp->id));
277                 putc('\n', file);
278         }
279         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX))
280                 putc(';', file);
281         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD2)) {
282                 fprintf(file, "; flags:");
283                 if (hp->qr)
284                         fprintf(file, " qr");
285                 if (hp->aa)
286                         fprintf(file, " aa");
287                 if (hp->tc)
288                         fprintf(file, " tc");
289                 if (hp->rd)
290                         fprintf(file, " rd");
291                 if (hp->ra)
292                         fprintf(file, " ra");
293         }
294         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD1)) {
295                 fprintf(file, "; Ques: %d", ntohs(hp->qdcount));
296                 fprintf(file, ", Ans: %d", ntohs(hp->ancount));
297                 fprintf(file, ", Auth: %d", ntohs(hp->nscount));
298                 fprintf(file, ", Addit: %d", ntohs(hp->arcount));
299         }
300         if ((!_res.pfcode) || (_res.pfcode &
301                 (RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) {
302                 putc('\n',file);
303         }
304         /*
305          * Print question records.
306          */
307         if (n = ntohs(hp->qdcount)) {
308                 if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
309                         fprintf(file, ";; QUESTIONS:\n");
310                 while (--n >= 0) {
311                         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
312                                 fprintf(file, ";;\t");
313                         TruncTest(cp);
314                         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
315                                 cp = p_cdnname(cp, msg, len, file);
316                         else {
317                                 int n;
318                                 char name[MAXDNAME];
319
320                                 if ((n = dn_expand(msg, msg+len, cp, name,
321                                                 sizeof name)) < 0)
322                                         cp = NULL;
323                                 else
324                                         cp += n;
325                         }
326                         ErrorTest(cp);
327                         TruncTest(cp);
328                         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
329                                 fprintf(file, ", type = %s",
330                                         __p_type(_getshort((u_char*)cp)));
331                         cp += INT16SZ;
332                         TruncTest(cp);
333                         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
334                                 fprintf(file, ", class = %s\n",
335                                         __p_class(_getshort((u_char*)cp)));
336                         cp += INT16SZ;
337                         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
338                                 putc('\n', file);
339                 }
340         }
341         /*
342          * Print authoritative answer records
343          */
344         TruncTest(cp);
345         cp = do_rrset(msg, len, cp, hp->ancount, RES_PRF_ANS, file,
346                       ";; ANSWERS:\n");
347         ErrorTest(cp);
348
349         /*
350          * print name server records
351          */
352         TruncTest(cp);
353         cp = do_rrset(msg, len, cp, hp->nscount, RES_PRF_AUTH, file,
354                       ";; AUTHORITY RECORDS:\n");
355         ErrorTest(cp);
356
357         TruncTest(cp);
358         /*
359          * print additional records
360          */
361         cp = do_rrset(msg, len, cp, hp->arcount, RES_PRF_ADD, file,
362                       ";; ADDITIONAL RECORDS:\n");
363         ErrorTest(cp);
364         return;
365  trunc:
366         fprintf(file, "\n;; ...truncated\n");
367         return;
368  error:
369         fprintf(file, "\n;; ...malformed\n");
370 }
371
372 void
373 __fp_query(msg, file)
374         const u_char *msg;
375         FILE *file;
376 {
377         fp_nquery(msg, PACKETSZ, file);
378 }
379
380 const u_char *
381 __p_cdnname(cp, msg, len, file)
382         const u_char *cp, *msg;
383         int len;
384         FILE *file;
385 {
386         char name[MAXDNAME];
387         int n;
388
389         if ((n = dn_expand(msg, msg + len, cp, name, sizeof name)) < 0)
390                 return (NULL);
391         if (name[0] == '\0')
392                 putc('.', file);
393         else
394                 fputs(name, file);
395         return (cp + n);
396 }
397
398 const u_char *
399 __p_cdname(cp, msg, file)
400         const u_char *cp, *msg;
401         FILE *file;
402 {
403         return (p_cdnname(cp, msg, PACKETSZ, file));
404 }
405
406 /* XXX: the rest of these functions need to become length-limited, too. (vix)
407  */
408
409 const u_char *
410 __p_fqname(cp, msg, file)
411         const u_char *cp, *msg;
412         FILE *file;
413 {
414         char name[MAXDNAME];
415         int n;
416
417         if ((n = dn_expand(msg, cp + MAXCDNAME, cp, name, sizeof name)) < 0)
418                 return (NULL);
419         if (name[0] == '\0') {
420                 putc('.', file);
421         } else {
422                 fputs(name, file);
423                 if (name[strlen(name) - 1] != '.')
424                         putc('.', file);
425         }
426         return (cp + n);
427 }
428
429 /*
430  * Print resource record fields in human readable form.
431  */
432 const u_char *
433 __p_rr(cp, msg, file)
434         const u_char *cp, *msg;
435         FILE *file;
436 {
437         int type, class, dlen, n, c;
438         struct in_addr inaddr;
439         const u_char *cp1, *cp2;
440         u_int32_t tmpttl, t;
441         int lcnt;
442
443         if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
444                 h_errno = NETDB_INTERNAL;
445                 return (NULL);
446         }
447         if ((cp = p_fqname(cp, msg, file)) == NULL)
448                 return (NULL);                  /* compression error */
449         type = _getshort((u_char*)cp);
450         cp += INT16SZ;
451         class = _getshort((u_char*)cp);
452         cp += INT16SZ;
453         tmpttl = _getlong((u_char*)cp);
454         cp += INT32SZ;
455         dlen = _getshort((u_char*)cp);
456         cp += INT16SZ;
457         cp1 = cp;
458         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_TTLID))
459                 fprintf(file, "\t%lu", (u_long)tmpttl);
460         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_CLASS))
461                 fprintf(file, "\t%s", __p_class(class));
462         fprintf(file, "\t%s", __p_type(type));
463         /*
464          * Print type specific data, if appropriate
465          */
466         switch (type) {
467         case T_A:
468                 switch (class) {
469                 case C_IN:
470                 case C_HS:
471                         bcopy(cp, (char *)&inaddr, INADDRSZ);
472                         if (dlen == 4) {
473                                 fprintf(file, "\t%s", inet_ntoa(inaddr));
474                                 cp += dlen;
475                         } else if (dlen == 7) {
476                                 char *address;
477                                 u_char protocol;
478                                 u_short port;
479
480                                 address = inet_ntoa(inaddr);
481                                 cp += INADDRSZ;
482                                 protocol = *(u_char*)cp;
483                                 cp += sizeof(u_char);
484                                 port = _getshort((u_char*)cp);
485                                 cp += INT16SZ;
486                                 fprintf(file, "\t%s\t; proto %d, port %d",
487                                         address, protocol, port);
488                         }
489                         break;
490                 default:
491                         cp += dlen;
492                 }
493                 break;
494         case T_CNAME:
495         case T_MB:
496         case T_MG:
497         case T_MR:
498         case T_NS:
499         case T_PTR:
500                 putc('\t', file);
501                 if ((cp = p_fqname(cp, msg, file)) == NULL)
502                         return (NULL);
503                 break;
504
505         case T_HINFO:
506         case T_ISDN:
507                 (void) fputs("\t\"", file);
508                 cp2 = cp + dlen;
509                 if ((n = (unsigned char) *cp++) != 0) {
510                         for (c = n; c > 0 && cp < cp2; c--) {
511                                 if (strchr("\n\"\\", *cp))
512                                         (void) putc('\\', file);
513                                 (void) putc(*cp++, file);
514                         }
515                         putc('"', file);
516                 }
517                 if (cp < cp2 && (n = (unsigned char) *cp++) != 0) {
518                         (void) fputs ("\t\"", file);
519                         for (c = n; c > 0 && cp < cp2; c--) {
520                                 if (strchr("\n\"\\", *cp))
521                                         (void) putc('\\', file);
522                                 (void) putc(*cp++, file);
523                         }
524                         putc('"', file);
525                 } else if (type == T_HINFO) {
526                         (void) fputs("\"?\"", file);
527                         fprintf(file, "\n;; *** Warning *** OS-type missing");
528                 }
529                 break;
530
531         case T_SOA:
532                 putc('\t', file);
533                 if ((cp = p_fqname(cp, msg, file)) == NULL)
534                         return (NULL);
535                 putc(' ', file);
536                 if ((cp = p_fqname(cp, msg, file)) == NULL)
537                         return (NULL);
538                 fputs(" (\n", file);
539                 t = _getlong((u_char*)cp);  cp += INT32SZ;
540                 fprintf(file, "\t\t\t%lu\t; serial\n", (u_long)t);
541                 t = _getlong((u_char*)cp);  cp += INT32SZ;
542                 fprintf(file, "\t\t\t%lu\t; refresh (%s)\n",
543                         (u_long)t, __p_time(t));
544                 t = _getlong((u_char*)cp);  cp += INT32SZ;
545                 fprintf(file, "\t\t\t%lu\t; retry (%s)\n",
546                         (u_long)t, __p_time(t));
547                 t = _getlong((u_char*)cp);  cp += INT32SZ;
548                 fprintf(file, "\t\t\t%lu\t; expire (%s)\n",
549                         (u_long)t, __p_time(t));
550                 t = _getlong((u_char*)cp);  cp += INT32SZ;
551                 fprintf(file, "\t\t\t%lu )\t; minimum (%s)",
552                         (u_long)t, __p_time(t));
553                 break;
554
555         case T_MX:
556         case T_AFSDB:
557         case T_RT:
558                 fprintf(file, "\t%d ", _getshort((u_char*)cp));
559                 cp += INT16SZ;
560                 if ((cp = p_fqname(cp, msg, file)) == NULL)
561                         return (NULL);
562                 break;
563
564         case T_PX:
565                 fprintf(file, "\t%d ", _getshort((u_char*)cp));
566                 cp += INT16SZ;
567                 if ((cp = p_fqname(cp, msg, file)) == NULL)
568                         return (NULL);
569                 putc(' ', file);
570                 if ((cp = p_fqname(cp, msg, file)) == NULL)
571                         return (NULL);
572                 break;
573
574         case T_TXT:
575         case T_X25:
576                 (void) fputs("\t\"", file);
577                 cp2 = cp1 + dlen;
578                 while (cp < cp2) {
579                         if (n = (unsigned char) *cp++) {
580                                 for (c = n; c > 0 && cp < cp2; c--) {
581                                         if (strchr("\n\"\\", *cp))
582                                                 (void) putc('\\', file);
583                                         (void) putc(*cp++, file);
584                                 }
585                         }
586                 }
587                 putc('"', file);
588                 break;
589
590         case T_NSAP:
591                 (void) fprintf(file, "\t%s", inet_nsap_ntoa(dlen, cp, NULL));
592                 cp += dlen;
593                 break;
594
595         case T_AAAA: {
596                 char t[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
597
598                 fprintf(file, "\t%s\n", inet_ntop(AF_INET6, cp, t, sizeof t));
599                 cp += dlen;
600                 break;
601         }
602
603         case T_LOC: {
604                 char t[255];
605
606                 (void) fprintf(file, "\t%s\n", loc_ntoa(cp, t));
607                 cp += dlen;
608                 break;
609         }
610
611         case T_MINFO:
612         case T_RP:
613                 putc('\t', file);
614                 if ((cp = p_fqname(cp, msg, file)) == NULL)
615                         return (NULL);
616                 putc(' ', file);
617                 if ((cp = p_fqname(cp, msg, file)) == NULL)
618                         return (NULL);
619                 break;
620
621         case T_UINFO:
622                 putc('\t', file);
623                 fputs((char *)cp, file);
624                 cp += dlen;
625                 break;
626
627         case T_UID:
628         case T_GID:
629                 if (dlen == 4) {
630                         fprintf(file, "\t%u", _getlong((u_char*)cp));
631                         cp += INT32SZ;
632                 }
633                 break;
634
635         case T_WKS:
636                 if (dlen < INT32SZ + 1)
637                         break;
638                 bcopy(cp, (char *)&inaddr, INADDRSZ);
639                 cp += INT32SZ;
640                 fprintf(file, "\t%s %s ( ",
641                         inet_ntoa(inaddr),
642                         deproto((int) *cp));
643                 cp += sizeof(u_char);
644                 n = 0;
645                 lcnt = 0;
646                 while (cp < cp1 + dlen) {
647                         c = *cp++;
648                         do {
649                                 if (c & 0200) {
650                                         if (lcnt == 0) {
651                                                 fputs("\n\t\t\t", file);
652                                                 lcnt = 5;
653                                         }
654                                         fputs(dewks(n), file);
655                                         putc(' ', file);
656                                         lcnt--;
657                                 }
658                                 c <<= 1;
659                         } while (++n & 07);
660                 }
661                 putc(')', file);
662                 break;
663
664 #ifdef ALLOW_T_UNSPEC
665         case T_UNSPEC:
666                 {
667                         int NumBytes = 8;
668                         u_char *DataPtr;
669                         int i;
670
671                         if (dlen < NumBytes) NumBytes = dlen;
672                         fprintf(file, "\tFirst %d bytes of hex data:",
673                                 NumBytes);
674                         for (i = 0, DataPtr = cp; i < NumBytes; i++, DataPtr++)
675                                 fprintf(file, " %x", *DataPtr);
676                         cp += dlen;
677                 }
678                 break;
679 #endif /* ALLOW_T_UNSPEC */
680
681         default:
682                 fprintf(file, "\t?%d?", type);
683                 cp += dlen;
684         }
685 #if 0
686         fprintf(file, "\t; dlen=%d, ttl %s\n", dlen, __p_time(tmpttl));
687 #else
688         putc('\n', file);
689 #endif
690         if (cp - cp1 != dlen) {
691                 fprintf(file, ";; packet size error (found %d, dlen was %d)\n",
692                         cp - cp1, dlen);
693                 cp = NULL;
694         }
695         return (cp);
696 }
697
698 /*
699  * Return a string for the type
700  */
701 const char *
702 __p_type(type)
703         int type;
704 {
705         static char nbuf[20];
706
707         switch (type) {
708         case T_A:       return "A";
709         case T_NS:      return "NS";
710         case T_CNAME:   return "CNAME";
711         case T_SOA:     return "SOA";
712         case T_MB:      return "MB";
713         case T_MG:      return "MG";
714         case T_MR:      return "MR";
715         case T_NULL:    return "NULL";
716         case T_WKS:     return "WKS";
717         case T_PTR:     return "PTR";
718         case T_HINFO:   return "HINFO";
719         case T_MINFO:   return "MINFO";
720         case T_MX:      return "MX";
721         case T_TXT:     return "TXT";
722         case T_RP:      return "RP";
723         case T_AFSDB:   return "AFSDB";
724         case T_X25:     return "X25";
725         case T_ISDN:    return "ISDN";
726         case T_RT:      return "RT";
727         case T_NSAP:    return "NSAP";
728         case T_NSAP_PTR: return "NSAP_PTR";
729         case T_SIG:     return "SIG";
730         case T_KEY:     return "KEY";
731         case T_PX:      return "PX";
732         case T_GPOS:    return "GPOS";
733         case T_AAAA:    return "AAAA";
734         case T_LOC:     return "LOC";
735         case T_AXFR:    return "AXFR";
736         case T_MAILB:   return "MAILB";
737         case T_MAILA:   return "MAILA";
738         case T_ANY:     return "ANY";
739         case T_UINFO:   return "UINFO";
740         case T_UID:     return "UID";
741         case T_GID:     return "GID";
742 #ifdef ALLOW_T_UNSPEC
743         case T_UNSPEC:  return "UNSPEC";
744 #endif /* ALLOW_T_UNSPEC */
745         default:        (void)sprintf(nbuf, "%d", type); return (nbuf);
746         }
747 }
748
749 /*
750  * Return a mnemonic for class
751  */
752 const char *
753 __p_class(class)
754         int class;
755 {
756         static char nbuf[20];
757
758         switch (class) {
759         case C_IN:      return "IN";
760         case C_HS:      return "HS";
761         case C_ANY:     return "ANY";
762         default:        (void)sprintf(nbuf, "%d", class); return (nbuf);
763         }
764 }
765
766 /*
767  * Return a mnemonic for an option
768  */
769 const char *
770 __p_option(option)
771         u_long option;
772 {
773         static char nbuf[40];
774
775         switch (option) {
776         case RES_INIT:          return "init";
777         case RES_DEBUG:         return "debug";
778         case RES_AAONLY:        return "aaonly(unimpl)";
779         case RES_USEVC:         return "usevc";
780         case RES_PRIMARY:       return "primry(unimpl)";
781         case RES_IGNTC:         return "igntc";
782         case RES_RECURSE:       return "recurs";
783         case RES_DEFNAMES:      return "defnam";
784         case RES_STAYOPEN:      return "styopn";
785         case RES_DNSRCH:        return "dnsrch";
786         case RES_INSECURE1:     return "insecure1";
787         case RES_INSECURE2:     return "insecure2";
788         default:                sprintf(nbuf, "?0x%lx?", (u_long)option);
789                                 return (nbuf);
790         }
791 }
792
793 /*
794  * Return a mnemonic for a time to live
795  */
796 char *
797 __p_time(value)
798         u_int32_t value;
799 {
800         static char nbuf[40];
801         int secs, mins, hours, days;
802         register char *p;
803
804         if (value == 0) {
805                 strcpy(nbuf, "0 secs");
806                 return (nbuf);
807         }
808
809         secs = value % 60;
810         value /= 60;
811         mins = value % 60;
812         value /= 60;
813         hours = value % 24;
814         value /= 24;
815         days = value;
816         value = 0;
817
818 #define PLURALIZE(x)    x, (x == 1) ? "" : "s"
819         p = nbuf;
820         if (days) {
821                 (void)sprintf(p, "%d day%s", PLURALIZE(days));
822                 while (*++p);
823         }
824         if (hours) {
825                 if (days)
826                         *p++ = ' ';
827                 (void)sprintf(p, "%d hour%s", PLURALIZE(hours));
828                 while (*++p);
829         }
830         if (mins) {
831                 if (days || hours)
832                         *p++ = ' ';
833                 (void)sprintf(p, "%d min%s", PLURALIZE(mins));
834                 while (*++p);
835         }
836         if (secs || ! (days || hours || mins)) {
837                 if (days || hours || mins)
838                         *p++ = ' ';
839                 (void)sprintf(p, "%d sec%s", PLURALIZE(secs));
840         }
841         return (nbuf);
842 }
843
844 /*
845  * routines to convert between on-the-wire RR format and zone file format.
846  * Does not contain conversion to/from decimal degrees; divide or multiply
847  * by 60*60*1000 for that.
848  */
849
850 static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
851                                       1000000,10000000,100000000,1000000000};
852
853 /* takes an XeY precision/size value, returns a string representation. */
854 static const char *
855 precsize_ntoa(prec)
856         u_int8_t prec;
857 {
858         static char retbuf[sizeof("90000000.00")];
859         unsigned long val;
860         int mantissa, exponent;
861
862         mantissa = (int)((prec >> 4) & 0x0f) % 10;
863         exponent = (int)((prec >> 0) & 0x0f) % 10;
864
865         val = mantissa * poweroften[exponent];
866
867         (void) sprintf(retbuf, "%ld.%.2ld", val/100, val%100);
868         return (retbuf);
869 }
870
871 /* converts ascii size/precision X * 10**Y(cm) to 0xXY.  moves pointer. */
872 static u_int8_t
873 precsize_aton(strptr)
874         char **strptr;
875 {
876         unsigned int mval = 0, cmval = 0;
877         u_int8_t retval = 0;
878         register char *cp;
879         register int exponent;
880         register int mantissa;
881
882         cp = *strptr;
883
884         while (isdigit(*cp))
885                 mval = mval * 10 + (*cp++ - '0');
886
887         if (*cp == '.') {               /* centimeters */
888                 cp++;
889                 if (isdigit(*cp)) {
890                         cmval = (*cp++ - '0') * 10;
891                         if (isdigit(*cp)) {
892                                 cmval += (*cp++ - '0');
893                         }
894                 }
895         }
896         cmval = (mval * 100) + cmval;
897
898         for (exponent = 0; exponent < 9; exponent++)
899                 if (cmval < poweroften[exponent+1])
900                         break;
901
902         mantissa = cmval / poweroften[exponent];
903         if (mantissa > 9)
904                 mantissa = 9;
905
906         retval = (mantissa << 4) | exponent;
907
908         *strptr = cp;
909
910         return (retval);
911 }
912
913 /* converts ascii lat/lon to unsigned encoded 32-bit number.  moves pointer. */
914 static u_int32_t
915 latlon2ul(latlonstrptr,which)
916         char **latlonstrptr;
917         int *which;
918 {
919         register char *cp;
920         u_int32_t retval;
921         int deg = 0, min = 0, secs = 0, secsfrac = 0;
922
923         cp = *latlonstrptr;
924
925         while (isdigit(*cp))
926                 deg = deg * 10 + (*cp++ - '0');
927
928         while (isspace(*cp))
929                 cp++;
930
931         if (!(isdigit(*cp)))
932                 goto fndhemi;
933
934         while (isdigit(*cp))
935                 min = min * 10 + (*cp++ - '0');
936
937         while (isspace(*cp))
938                 cp++;
939
940         if (!(isdigit(*cp)))
941                 goto fndhemi;
942
943         while (isdigit(*cp))
944                 secs = secs * 10 + (*cp++ - '0');
945
946         if (*cp == '.') {               /* decimal seconds */
947                 cp++;
948                 if (isdigit(*cp)) {
949                         secsfrac = (*cp++ - '0') * 100;
950                         if (isdigit(*cp)) {
951                                 secsfrac += (*cp++ - '0') * 10;
952                                 if (isdigit(*cp)) {
953                                         secsfrac += (*cp++ - '0');
954                                 }
955                         }
956                 }
957         }
958
959         while (!isspace(*cp))   /* if any trailing garbage */
960                 cp++;
961
962         while (isspace(*cp))
963                 cp++;
964
965  fndhemi:
966         switch (*cp) {
967         case 'N': case 'n':
968         case 'E': case 'e':
969                 retval = ((unsigned)1<<31)
970                         + (((((deg * 60) + min) * 60) + secs) * 1000)
971                         + secsfrac;
972                 break;
973         case 'S': case 's':
974         case 'W': case 'w':
975                 retval = ((unsigned)1<<31)
976                         - (((((deg * 60) + min) * 60) + secs) * 1000)
977                         - secsfrac;
978                 break;
979         default:
980                 retval = 0;     /* invalid value -- indicates error */
981                 break;
982         }
983
984         switch (*cp) {
985         case 'N': case 'n':
986         case 'S': case 's':
987                 *which = 1;     /* latitude */
988                 break;
989         case 'E': case 'e':
990         case 'W': case 'w':
991                 *which = 2;     /* longitude */
992                 break;
993         default:
994                 *which = 0;     /* error */
995                 break;
996         }
997
998         cp++;                   /* skip the hemisphere */
999
1000         while (!isspace(*cp))   /* if any trailing garbage */
1001                 cp++;
1002
1003         while (isspace(*cp))    /* move to next field */
1004                 cp++;
1005
1006         *latlonstrptr = cp;
1007
1008         return (retval);
1009 }
1010
1011 /* converts a zone file representation in a string to an RDATA on-the-wire
1012  * representation. */
1013 int
1014 loc_aton(ascii, binary)
1015         const char *ascii;
1016         u_char *binary;
1017 {
1018         const char *cp, *maxcp;
1019         u_char *bcp;
1020
1021         u_int32_t latit = 0, longit = 0, alt = 0;
1022         u_int32_t lltemp1 = 0, lltemp2 = 0;
1023         int altmeters = 0, altfrac = 0, altsign = 1;
1024         u_int8_t hp = 0x16;     /* default = 1e6 cm = 10000.00m = 10km */
1025         u_int8_t vp = 0x13;     /* default = 1e3 cm = 10.00m */
1026         u_int8_t siz = 0x12;    /* default = 1e2 cm = 1.00m */
1027         int which1 = 0, which2 = 0;
1028
1029         cp = ascii;
1030         maxcp = cp + strlen(ascii);
1031
1032         lltemp1 = latlon2ul(&cp, &which1);
1033
1034         lltemp2 = latlon2ul(&cp, &which2);
1035
1036         switch (which1 + which2) {
1037         case 3:                 /* 1 + 2, the only valid combination */
1038                 if ((which1 == 1) && (which2 == 2)) { /* normal case */
1039                         latit = lltemp1;
1040                         longit = lltemp2;
1041                 } else if ((which1 == 2) && (which2 == 1)) { /* reversed */
1042                         longit = lltemp1;
1043                         latit = lltemp2;
1044                 } else {        /* some kind of brokenness */
1045                         return 0;
1046                 }
1047                 break;
1048         default:                /* we didn't get one of each */
1049                 return 0;
1050         }
1051
1052         /* altitude */
1053         if (*cp == '-') {
1054                 altsign = -1;
1055                 cp++;
1056         }
1057
1058         if (*cp == '+')
1059                 cp++;
1060
1061         while (isdigit(*cp))
1062                 altmeters = altmeters * 10 + (*cp++ - '0');
1063
1064         if (*cp == '.') {               /* decimal meters */
1065                 cp++;
1066                 if (isdigit(*cp)) {
1067                         altfrac = (*cp++ - '0') * 10;
1068                         if (isdigit(*cp)) {
1069                                 altfrac += (*cp++ - '0');
1070                         }
1071                 }
1072         }
1073
1074         alt = (10000000 + (altsign * (altmeters * 100 + altfrac)));
1075
1076         while (!isspace(*cp) && (cp < maxcp)) /* if trailing garbage or m */
1077                 cp++;
1078
1079         while (isspace(*cp) && (cp < maxcp))
1080                 cp++;
1081
1082         if (cp >= maxcp)
1083                 goto defaults;
1084
1085         siz = precsize_aton(&cp);
1086
1087         while (!isspace(*cp) && (cp < maxcp))   /* if trailing garbage or m */
1088                 cp++;
1089
1090         while (isspace(*cp) && (cp < maxcp))
1091                 cp++;
1092
1093         if (cp >= maxcp)
1094                 goto defaults;
1095
1096         hp = precsize_aton(&cp);
1097
1098         while (!isspace(*cp) && (cp < maxcp))   /* if trailing garbage or m */
1099                 cp++;
1100
1101         while (isspace(*cp) && (cp < maxcp))
1102                 cp++;
1103
1104         if (cp >= maxcp)
1105                 goto defaults;
1106
1107         vp = precsize_aton(&cp);
1108
1109  defaults:
1110
1111         bcp = binary;
1112         *bcp++ = (u_int8_t) 0;  /* version byte */
1113         *bcp++ = siz;
1114         *bcp++ = hp;
1115         *bcp++ = vp;
1116         PUTLONG(latit,bcp);
1117         PUTLONG(longit,bcp);
1118         PUTLONG(alt,bcp);
1119
1120         return (16);            /* size of RR in octets */
1121 }
1122
1123 /* takes an on-the-wire LOC RR and formats it in a human readable format. */
1124 char *
1125 loc_ntoa(binary, ascii)
1126         const u_char *binary;
1127         char *ascii;
1128 {
1129         static char *error = "?";
1130         register const u_char *cp = binary;
1131
1132         int latdeg, latmin, latsec, latsecfrac;
1133         int longdeg, longmin, longsec, longsecfrac;
1134         char northsouth, eastwest;
1135         int altmeters, altfrac, altsign;
1136
1137         const int referencealt = 100000 * 100;
1138
1139         int32_t latval, longval, altval;
1140         u_int32_t templ;
1141         u_int8_t sizeval, hpval, vpval, versionval;
1142
1143         char *sizestr, *hpstr, *vpstr;
1144
1145         versionval = *cp++;
1146
1147         if (versionval) {
1148                 sprintf(ascii, "; error: unknown LOC RR version");
1149                 return (ascii);
1150         }
1151
1152         sizeval = *cp++;
1153
1154         hpval = *cp++;
1155         vpval = *cp++;
1156
1157         GETLONG(templ, cp);
1158         latval = (templ - ((unsigned)1<<31));
1159
1160         GETLONG(templ, cp);
1161         longval = (templ - ((unsigned)1<<31));
1162
1163         GETLONG(templ, cp);
1164         if (templ < referencealt) { /* below WGS 84 spheroid */
1165                 altval = referencealt - templ;
1166                 altsign = -1;
1167         } else {
1168                 altval = templ - referencealt;
1169                 altsign = 1;
1170         }
1171
1172         if (latval < 0) {
1173                 northsouth = 'S';
1174                 latval = -latval;
1175         } else
1176                 northsouth = 'N';
1177
1178         latsecfrac = latval % 1000;
1179         latval = latval / 1000;
1180         latsec = latval % 60;
1181         latval = latval / 60;
1182         latmin = latval % 60;
1183         latval = latval / 60;
1184         latdeg = latval;
1185
1186         if (longval < 0) {
1187                 eastwest = 'W';
1188                 longval = -longval;
1189         } else
1190                 eastwest = 'E';
1191
1192         longsecfrac = longval % 1000;
1193         longval = longval / 1000;
1194         longsec = longval % 60;
1195         longval = longval / 60;
1196         longmin = longval % 60;
1197         longval = longval / 60;
1198         longdeg = longval;
1199
1200         altfrac = altval % 100;
1201         altmeters = (altval / 100) * altsign;
1202
1203         if ((sizestr = strdup(precsize_ntoa(sizeval))) == NULL)
1204                 sizestr = error;
1205         if ((hpstr = strdup(precsize_ntoa(hpval))) == NULL)
1206                 hpstr = error;
1207         if ((vpstr = strdup(precsize_ntoa(vpval))) == NULL)
1208                 vpstr = error;
1209
1210         sprintf(ascii,
1211               "%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %d.%.2dm %sm %sm %sm",
1212                 latdeg, latmin, latsec, latsecfrac, northsouth,
1213                 longdeg, longmin, longsec, longsecfrac, eastwest,
1214                 altmeters, altfrac, sizestr, hpstr, vpstr);
1215
1216         if (sizestr != error)
1217                 free(sizestr);
1218         if (hpstr != error)
1219                 free(hpstr);
1220         if (vpstr != error)
1221                 free(vpstr);
1222
1223         return (ascii);
1224 }