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