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