Thu May 23 00:01:10 1996 Ulrich Drepper <drepper@cygnus.com>
[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                 break;
600         }
601
602         case T_MINFO:
603         case T_RP:
604                 putc('\t', file);
605                 if ((cp = p_fqname(cp, msg, file)) == NULL)
606                         return (NULL);
607                 putc(' ', file);
608                 if ((cp = p_fqname(cp, msg, file)) == NULL)
609                         return (NULL);
610                 break;
611
612         case T_UINFO:
613                 putc('\t', file);
614                 fputs((char *)cp, file);
615                 cp += dlen;
616                 break;
617
618         case T_UID:
619         case T_GID:
620                 if (dlen == 4) {
621                         fprintf(file, "\t%u", _getlong((u_char*)cp));
622                         cp += INT32SZ;
623                 }
624                 break;
625
626         case T_WKS:
627                 if (dlen < INT32SZ + 1)
628                         break;
629                 bcopy(cp, (char *)&inaddr, INADDRSZ);
630                 cp += INT32SZ;
631                 fprintf(file, "\t%s %s ( ",
632                         inet_ntoa(inaddr),
633                         deproto((int) *cp));
634                 cp += sizeof(u_char);
635                 n = 0;
636                 lcnt = 0;
637                 while (cp < cp1 + dlen) {
638                         c = *cp++;
639                         do {
640                                 if (c & 0200) {
641                                         if (lcnt == 0) {
642                                                 fputs("\n\t\t\t", file);
643                                                 lcnt = 5;
644                                         }
645                                         fputs(dewks(n), file);
646                                         putc(' ', file);
647                                         lcnt--;
648                                 }
649                                 c <<= 1;
650                         } while (++n & 07);
651                 }
652                 putc(')', file);
653                 break;
654
655 #ifdef ALLOW_T_UNSPEC
656         case T_UNSPEC:
657                 {
658                         int NumBytes = 8;
659                         u_char *DataPtr;
660                         int i;
661
662                         if (dlen < NumBytes) NumBytes = dlen;
663                         fprintf(file, "\tFirst %d bytes of hex data:",
664                                 NumBytes);
665                         for (i = 0, DataPtr = cp; i < NumBytes; i++, DataPtr++)
666                                 fprintf(file, " %x", *DataPtr);
667                         cp += dlen;
668                 }
669                 break;
670 #endif /* ALLOW_T_UNSPEC */
671
672         default:
673                 fprintf(file, "\t?%d?", type);
674                 cp += dlen;
675         }
676 #if 0
677         fprintf(file, "\t; dlen=%d, ttl %s\n", dlen, __p_time(tmpttl));
678 #else
679         putc('\n', file);
680 #endif
681         if (cp - cp1 != dlen) {
682                 fprintf(file, ";; packet size error (found %d, dlen was %d)\n",
683                         cp - cp1, dlen);
684                 cp = NULL;
685         }
686         return (cp);
687 }
688
689 /*
690  * Return a string for the type
691  */
692 const char *
693 __p_type(type)
694         int type;
695 {
696         static char nbuf[20];
697
698         switch (type) {
699         case T_A:       return "A";
700         case T_NS:      return "NS";
701         case T_CNAME:   return "CNAME";
702         case T_SOA:     return "SOA";
703         case T_MB:      return "MB";
704         case T_MG:      return "MG";
705         case T_MR:      return "MR";
706         case T_NULL:    return "NULL";
707         case T_WKS:     return "WKS";
708         case T_PTR:     return "PTR";
709         case T_HINFO:   return "HINFO";
710         case T_MINFO:   return "MINFO";
711         case T_MX:      return "MX";
712         case T_TXT:     return "TXT";
713         case T_RP:      return "RP";
714         case T_AFSDB:   return "AFSDB";
715         case T_X25:     return "X25";
716         case T_ISDN:    return "ISDN";
717         case T_RT:      return "RT";
718         case T_NSAP:    return "NSAP";
719         case T_NSAP_PTR: return "NSAP_PTR";
720         case T_SIG:     return "SIG";
721         case T_KEY:     return "KEY";
722         case T_PX:      return "PX";
723         case T_GPOS:    return "GPOS";
724         case T_AAAA:    return "AAAA";
725         case T_LOC:     return "LOC";
726         case T_AXFR:    return "AXFR";
727         case T_MAILB:   return "MAILB";
728         case T_MAILA:   return "MAILA";
729         case T_ANY:     return "ANY";
730         case T_UINFO:   return "UINFO";
731         case T_UID:     return "UID";
732         case T_GID:     return "GID";
733 #ifdef ALLOW_T_UNSPEC
734         case T_UNSPEC:  return "UNSPEC";
735 #endif /* ALLOW_T_UNSPEC */
736         default:        (void)sprintf(nbuf, "%d", type); return (nbuf);
737         }
738 }
739
740 /*
741  * Return a mnemonic for class
742  */
743 const char *
744 __p_class(class)
745         int class;
746 {
747         static char nbuf[20];
748
749         switch (class) {
750         case C_IN:      return "IN";
751         case C_HS:      return "HS";
752         case C_ANY:     return "ANY";
753         default:        (void)sprintf(nbuf, "%d", class); return (nbuf);
754         }
755 }
756
757 /*
758  * Return a mnemonic for an option
759  */
760 const char *
761 __p_option(option)
762         u_long option;
763 {
764         static char nbuf[40];
765
766         switch (option) {
767         case RES_INIT:          return "init";
768         case RES_DEBUG:         return "debug";
769         case RES_AAONLY:        return "aaonly(unimpl)";
770         case RES_USEVC:         return "usevc";
771         case RES_PRIMARY:       return "primry(unimpl)";
772         case RES_IGNTC:         return "igntc";
773         case RES_RECURSE:       return "recurs";
774         case RES_DEFNAMES:      return "defnam";
775         case RES_STAYOPEN:      return "styopn";
776         case RES_DNSRCH:        return "dnsrch";
777         case RES_INSECURE1:     return "insecure1";
778         case RES_INSECURE2:     return "insecure2";
779         default:                sprintf(nbuf, "?0x%lx?", (u_long)option);
780                                 return (nbuf);
781         }
782 }
783
784 /*
785  * Return a mnemonic for a time to live
786  */
787 char *
788 __p_time(value)
789         u_int32_t value;
790 {
791         static char nbuf[40];
792         int secs, mins, hours, days;
793         register char *p;
794
795         if (value == 0) {
796                 strcpy(nbuf, "0 secs");
797                 return (nbuf);
798         }
799
800         secs = value % 60;
801         value /= 60;
802         mins = value % 60;
803         value /= 60;
804         hours = value % 24;
805         value /= 24;
806         days = value;
807         value = 0;
808
809 #define PLURALIZE(x)    x, (x == 1) ? "" : "s"
810         p = nbuf;
811         if (days) {
812                 (void)sprintf(p, "%d day%s", PLURALIZE(days));
813                 while (*++p);
814         }
815         if (hours) {
816                 if (days)
817                         *p++ = ' ';
818                 (void)sprintf(p, "%d hour%s", PLURALIZE(hours));
819                 while (*++p);
820         }
821         if (mins) {
822                 if (days || hours)
823                         *p++ = ' ';
824                 (void)sprintf(p, "%d min%s", PLURALIZE(mins));
825                 while (*++p);
826         }
827         if (secs || ! (days || hours || mins)) {
828                 if (days || hours || mins)
829                         *p++ = ' ';
830                 (void)sprintf(p, "%d sec%s", PLURALIZE(secs));
831         }
832         return (nbuf);
833 }