Sat Jun 15 18:13:43 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
[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, ";; packet size error (found %d, dlen was %d)\n",
693                         cp - cp1, dlen);
694                 cp = NULL;
695         }
696         return (cp);
697 }
698
699 /*
700  * Return a string for the type
701  */
702 const char *
703 __p_type(type)
704         int type;
705 {
706         static char nbuf[20];
707
708         switch (type) {
709         case T_A:       return "A";
710         case T_NS:      return "NS";
711         case T_CNAME:   return "CNAME";
712         case T_SOA:     return "SOA";
713         case T_MB:      return "MB";
714         case T_MG:      return "MG";
715         case T_MR:      return "MR";
716         case T_NULL:    return "NULL";
717         case T_WKS:     return "WKS";
718         case T_PTR:     return "PTR";
719         case T_HINFO:   return "HINFO";
720         case T_MINFO:   return "MINFO";
721         case T_MX:      return "MX";
722         case T_TXT:     return "TXT";
723         case T_RP:      return "RP";
724         case T_AFSDB:   return "AFSDB";
725         case T_X25:     return "X25";
726         case T_ISDN:    return "ISDN";
727         case T_RT:      return "RT";
728         case T_NSAP:    return "NSAP";
729         case T_NSAP_PTR: return "NSAP_PTR";
730         case T_SIG:     return "SIG";
731         case T_KEY:     return "KEY";
732         case T_PX:      return "PX";
733         case T_GPOS:    return "GPOS";
734         case T_AAAA:    return "AAAA";
735         case T_LOC:     return "LOC";
736         case T_AXFR:    return "AXFR";
737         case T_MAILB:   return "MAILB";
738         case T_MAILA:   return "MAILA";
739         case T_ANY:     return "ANY";
740         case T_UINFO:   return "UINFO";
741         case T_UID:     return "UID";
742         case T_GID:     return "GID";
743 #ifdef ALLOW_T_UNSPEC
744         case T_UNSPEC:  return "UNSPEC";
745 #endif /* ALLOW_T_UNSPEC */
746         default:        (void)sprintf(nbuf, "%d", type); return (nbuf);
747         }
748 }
749
750 /*
751  * Return a mnemonic for class
752  */
753 const char *
754 __p_class(class)
755         int class;
756 {
757         static char nbuf[20];
758
759         switch (class) {
760         case C_IN:      return "IN";
761         case C_HS:      return "HS";
762         case C_ANY:     return "ANY";
763         default:        (void)sprintf(nbuf, "%d", class); return (nbuf);
764         }
765 }
766
767 /*
768  * Return a mnemonic for an option
769  */
770 const char *
771 __p_option(option)
772         u_long option;
773 {
774         static char nbuf[40];
775
776         switch (option) {
777         case RES_INIT:          return "init";
778         case RES_DEBUG:         return "debug";
779         case RES_AAONLY:        return "aaonly(unimpl)";
780         case RES_USEVC:         return "usevc";
781         case RES_PRIMARY:       return "primry(unimpl)";
782         case RES_IGNTC:         return "igntc";
783         case RES_RECURSE:       return "recurs";
784         case RES_DEFNAMES:      return "defnam";
785         case RES_STAYOPEN:      return "styopn";
786         case RES_DNSRCH:        return "dnsrch";
787         case RES_INSECURE1:     return "insecure1";
788         case RES_INSECURE2:     return "insecure2";
789         default:                sprintf(nbuf, "?0x%lx?", (u_long)option);
790                                 return (nbuf);
791         }
792 }
793
794 /*
795  * Return a mnemonic for a time to live
796  */
797 char *
798 __p_time(value)
799         u_int32_t value;
800 {
801         static char nbuf[40];
802         int secs, mins, hours, days;
803         register char *p;
804
805         if (value == 0) {
806                 strcpy(nbuf, "0 secs");
807                 return (nbuf);
808         }
809
810         secs = value % 60;
811         value /= 60;
812         mins = value % 60;
813         value /= 60;
814         hours = value % 24;
815         value /= 24;
816         days = value;
817         value = 0;
818
819 #define PLURALIZE(x)    x, (x == 1) ? "" : "s"
820         p = nbuf;
821         if (days) {
822                 (void)sprintf(p, "%d day%s", PLURALIZE(days));
823                 while (*++p);
824         }
825         if (hours) {
826                 if (days)
827                         *p++ = ' ';
828                 (void)sprintf(p, "%d hour%s", PLURALIZE(hours));
829                 while (*++p);
830         }
831         if (mins) {
832                 if (days || hours)
833                         *p++ = ' ';
834                 (void)sprintf(p, "%d min%s", PLURALIZE(mins));
835                 while (*++p);
836         }
837         if (secs || ! (days || hours || mins)) {
838                 if (days || hours || mins)
839                         *p++ = ' ';
840                 (void)sprintf(p, "%d sec%s", PLURALIZE(secs));
841         }
842         return (nbuf);
843 }
844
845 /*
846  * routines to convert between on-the-wire RR format and zone file format.
847  * Does not contain conversion to/from decimal degrees; divide or multiply
848  * by 60*60*1000 for that.
849  */
850
851 static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
852                                       1000000,10000000,100000000,1000000000};
853
854 /* takes an XeY precision/size value, returns a string representation. */
855 static const char *
856 precsize_ntoa(prec)
857         u_int8_t prec;
858 {
859         static char retbuf[sizeof("90000000.00")];
860         unsigned long val;
861         int mantissa, exponent;
862
863         mantissa = (int)((prec >> 4) & 0x0f) % 10;
864         exponent = (int)((prec >> 0) & 0x0f) % 10;
865
866         val = mantissa * poweroften[exponent];
867
868         (void) sprintf(retbuf, "%ld.%.2ld", val/100, val%100);
869         return (retbuf);
870 }
871
872 /* converts ascii size/precision X * 10**Y(cm) to 0xXY.  moves pointer. */
873 static u_int8_t
874 precsize_aton(strptr)
875         char **strptr;
876 {
877         unsigned int mval = 0, cmval = 0;
878         u_int8_t retval = 0;
879         register char *cp;
880         register int exponent;
881         register int mantissa;
882
883         cp = *strptr;
884
885         while (isdigit(*cp))
886                 mval = mval * 10 + (*cp++ - '0');
887
888         if (*cp == '.') {               /* centimeters */
889                 cp++;
890                 if (isdigit(*cp)) {
891                         cmval = (*cp++ - '0') * 10;
892                         if (isdigit(*cp)) {
893                                 cmval += (*cp++ - '0');
894                         }
895                 }
896         }
897         cmval = (mval * 100) + cmval;
898
899         for (exponent = 0; exponent < 9; exponent++)
900                 if (cmval < poweroften[exponent+1])
901                         break;
902
903         mantissa = cmval / poweroften[exponent];
904         if (mantissa > 9)
905                 mantissa = 9;
906
907         retval = (mantissa << 4) | exponent;
908
909         *strptr = cp;
910
911         return (retval);
912 }
913
914 /* converts ascii lat/lon to unsigned encoded 32-bit number.  moves pointer. */
915 static u_int32_t
916 latlon2ul(latlonstrptr,which)
917         char **latlonstrptr;
918         int *which;
919 {
920         register char *cp;
921         u_int32_t retval;
922         int deg = 0, min = 0, secs = 0, secsfrac = 0;
923
924         cp = *latlonstrptr;
925
926         while (isdigit(*cp))
927                 deg = deg * 10 + (*cp++ - '0');
928
929         while (isspace(*cp))
930                 cp++;
931
932         if (!(isdigit(*cp)))
933                 goto fndhemi;
934
935         while (isdigit(*cp))
936                 min = min * 10 + (*cp++ - '0');
937
938         while (isspace(*cp))
939                 cp++;
940
941         if (!(isdigit(*cp)))
942                 goto fndhemi;
943
944         while (isdigit(*cp))
945                 secs = secs * 10 + (*cp++ - '0');
946
947         if (*cp == '.') {               /* decimal seconds */
948                 cp++;
949                 if (isdigit(*cp)) {
950                         secsfrac = (*cp++ - '0') * 100;
951                         if (isdigit(*cp)) {
952                                 secsfrac += (*cp++ - '0') * 10;
953                                 if (isdigit(*cp)) {
954                                         secsfrac += (*cp++ - '0');
955                                 }
956                         }
957                 }
958         }
959
960         while (!isspace(*cp))   /* if any trailing garbage */
961                 cp++;
962
963         while (isspace(*cp))
964                 cp++;
965
966  fndhemi:
967         switch (*cp) {
968         case 'N': case 'n':
969         case 'E': case 'e':
970                 retval = ((unsigned)1<<31)
971                         + (((((deg * 60) + min) * 60) + secs) * 1000)
972                         + secsfrac;
973                 break;
974         case 'S': case 's':
975         case 'W': case 'w':
976                 retval = ((unsigned)1<<31)
977                         - (((((deg * 60) + min) * 60) + secs) * 1000)
978                         - secsfrac;
979                 break;
980         default:
981                 retval = 0;     /* invalid value -- indicates error */
982                 break;
983         }
984
985         switch (*cp) {
986         case 'N': case 'n':
987         case 'S': case 's':
988                 *which = 1;     /* latitude */
989                 break;
990         case 'E': case 'e':
991         case 'W': case 'w':
992                 *which = 2;     /* longitude */
993                 break;
994         default:
995                 *which = 0;     /* error */
996                 break;
997         }
998
999         cp++;                   /* skip the hemisphere */
1000
1001         while (!isspace(*cp))   /* if any trailing garbage */
1002                 cp++;
1003
1004         while (isspace(*cp))    /* move to next field */
1005                 cp++;
1006
1007         *latlonstrptr = cp;
1008
1009         return (retval);
1010 }
1011
1012 /* converts a zone file representation in a string to an RDATA on-the-wire
1013  * representation. */
1014 int
1015 loc_aton(ascii, binary)
1016         const char *ascii;
1017         u_char *binary;
1018 {
1019         const char *cp, *maxcp;
1020         u_char *bcp;
1021
1022         u_int32_t latit = 0, longit = 0, alt = 0;
1023         u_int32_t lltemp1 = 0, lltemp2 = 0;
1024         int altmeters = 0, altfrac = 0, altsign = 1;
1025         u_int8_t hp = 0x16;     /* default = 1e6 cm = 10000.00m = 10km */
1026         u_int8_t vp = 0x13;     /* default = 1e3 cm = 10.00m */
1027         u_int8_t siz = 0x12;    /* default = 1e2 cm = 1.00m */
1028         int which1 = 0, which2 = 0;
1029
1030         cp = ascii;
1031         maxcp = cp + strlen(ascii);
1032
1033         lltemp1 = latlon2ul(&cp, &which1);
1034
1035         lltemp2 = latlon2ul(&cp, &which2);
1036
1037         switch (which1 + which2) {
1038         case 3:                 /* 1 + 2, the only valid combination */
1039                 if ((which1 == 1) && (which2 == 2)) { /* normal case */
1040                         latit = lltemp1;
1041                         longit = lltemp2;
1042                 } else if ((which1 == 2) && (which2 == 1)) { /* reversed */
1043                         longit = lltemp1;
1044                         latit = lltemp2;
1045                 } else {        /* some kind of brokenness */
1046                         return 0;
1047                 }
1048                 break;
1049         default:                /* we didn't get one of each */
1050                 return 0;
1051         }
1052
1053         /* altitude */
1054         if (*cp == '-') {
1055                 altsign = -1;
1056                 cp++;
1057         }
1058
1059         if (*cp == '+')
1060                 cp++;
1061
1062         while (isdigit(*cp))
1063                 altmeters = altmeters * 10 + (*cp++ - '0');
1064
1065         if (*cp == '.') {               /* decimal meters */
1066                 cp++;
1067                 if (isdigit(*cp)) {
1068                         altfrac = (*cp++ - '0') * 10;
1069                         if (isdigit(*cp)) {
1070                                 altfrac += (*cp++ - '0');
1071                         }
1072                 }
1073         }
1074
1075         alt = (10000000 + (altsign * (altmeters * 100 + altfrac)));
1076
1077         while (!isspace(*cp) && (cp < maxcp)) /* if trailing garbage or m */
1078                 cp++;
1079
1080         while (isspace(*cp) && (cp < maxcp))
1081                 cp++;
1082
1083         if (cp >= maxcp)
1084                 goto defaults;
1085
1086         siz = precsize_aton(&cp);
1087
1088         while (!isspace(*cp) && (cp < maxcp))   /* if trailing garbage or m */
1089                 cp++;
1090
1091         while (isspace(*cp) && (cp < maxcp))
1092                 cp++;
1093
1094         if (cp >= maxcp)
1095                 goto defaults;
1096
1097         hp = precsize_aton(&cp);
1098
1099         while (!isspace(*cp) && (cp < maxcp))   /* if trailing garbage or m */
1100                 cp++;
1101
1102         while (isspace(*cp) && (cp < maxcp))
1103                 cp++;
1104
1105         if (cp >= maxcp)
1106                 goto defaults;
1107
1108         vp = precsize_aton(&cp);
1109
1110  defaults:
1111
1112         bcp = binary;
1113         *bcp++ = (u_int8_t) 0;  /* version byte */
1114         *bcp++ = siz;
1115         *bcp++ = hp;
1116         *bcp++ = vp;
1117         PUTLONG(latit,bcp);
1118         PUTLONG(longit,bcp);
1119         PUTLONG(alt,bcp);
1120
1121         return (16);            /* size of RR in octets */
1122 }
1123
1124 /* takes an on-the-wire LOC RR and formats it in a human readable format. */
1125 char *
1126 loc_ntoa(binary, ascii)
1127         const u_char *binary;
1128         char *ascii;
1129 {
1130         static char *error = "?";
1131         register const u_char *cp = binary;
1132
1133         int latdeg, latmin, latsec, latsecfrac;
1134         int longdeg, longmin, longsec, longsecfrac;
1135         char northsouth, eastwest;
1136         int altmeters, altfrac, altsign;
1137
1138         const int referencealt = 100000 * 100;
1139
1140         int32_t latval, longval, altval;
1141         u_int32_t templ;
1142         u_int8_t sizeval, hpval, vpval, versionval;
1143
1144         char *sizestr, *hpstr, *vpstr;
1145
1146         versionval = *cp++;
1147
1148         if (versionval) {
1149                 sprintf(ascii, "; error: unknown LOC RR version");
1150                 return (ascii);
1151         }
1152
1153         sizeval = *cp++;
1154
1155         hpval = *cp++;
1156         vpval = *cp++;
1157
1158         GETLONG(templ, cp);
1159         latval = (templ - ((unsigned)1<<31));
1160
1161         GETLONG(templ, cp);
1162         longval = (templ - ((unsigned)1<<31));
1163
1164         GETLONG(templ, cp);
1165         if (templ < referencealt) { /* below WGS 84 spheroid */
1166                 altval = referencealt - templ;
1167                 altsign = -1;
1168         } else {
1169                 altval = templ - referencealt;
1170                 altsign = 1;
1171         }
1172
1173         if (latval < 0) {
1174                 northsouth = 'S';
1175                 latval = -latval;
1176         } else
1177                 northsouth = 'N';
1178
1179         latsecfrac = latval % 1000;
1180         latval = latval / 1000;
1181         latsec = latval % 60;
1182         latval = latval / 60;
1183         latmin = latval % 60;
1184         latval = latval / 60;
1185         latdeg = latval;
1186
1187         if (longval < 0) {
1188                 eastwest = 'W';
1189                 longval = -longval;
1190         } else
1191                 eastwest = 'E';
1192
1193         longsecfrac = longval % 1000;
1194         longval = longval / 1000;
1195         longsec = longval % 60;
1196         longval = longval / 60;
1197         longmin = longval % 60;
1198         longval = longval / 60;
1199         longdeg = longval;
1200
1201         altfrac = altval % 100;
1202         altmeters = (altval / 100) * altsign;
1203
1204         if ((sizestr = strdup(precsize_ntoa(sizeval))) == NULL)
1205                 sizestr = error;
1206         if ((hpstr = strdup(precsize_ntoa(hpval))) == NULL)
1207                 hpstr = error;
1208         if ((vpstr = strdup(precsize_ntoa(vpval))) == NULL)
1209                 vpstr = error;
1210
1211         sprintf(ascii,
1212               "%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %d.%.2dm %sm %sm %sm",
1213                 latdeg, latmin, latsec, latsecfrac, northsouth,
1214                 longdeg, longmin, longsec, longsecfrac, eastwest,
1215                 altmeters, altfrac, sizestr, hpstr, vpstr);
1216
1217         if (sizestr != error)
1218                 free(sizestr);
1219         if (hpstr != error)
1220                 free(hpstr);
1221         if (vpstr != error)
1222                 free(vpstr);
1223
1224         return (ascii);
1225 }