1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2015 Gary Mills
24 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
26 */
27
28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
30
31 /*
32 * University Copyright- Copyright (c) 1982, 1986, 1988
33 * The Regents of the University of California
34 * All Rights Reserved
35 *
36 * University Acknowledgment- Portions of this document are derived from
37 * software developed by the University of California, Berkeley, and its
38 * contributors.
39 */
40
41 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <arpa/nameser.h>
48 #include <resolv.h>
49 #include "crossl.h"
50
51 void fp_query(char *msg, FILE *file);
52
53 char *_res_opcodes[] = {
54 "QUERY",
55 "IQUERY",
56 "CQUERYM",
57 "CQUERYU",
58 "4",
59 "5",
60 "6",
61 "7",
62 "8",
63 "UPDATEA",
64 "UPDATED",
65 "UPDATEDA",
66 "UPDATEM",
67 "UPDATEMA",
68 "ZONEINIT",
69 "ZONEREF",
70 };
71
72 char *_res_resultcodes[] = {
73 "NOERROR",
74 "FORMERR",
75 "SERVFAIL",
76 "NXDOMAIN",
77 "NOTIMP",
78 "REFUSED",
79 "6",
80 "7",
81 "8",
82 "9",
83 "10",
84 "11",
85 "12",
86 "13",
87 "14",
88 "NOCHANGE",
89 };
90
91 void
p_query(msg)92 p_query(msg)
93 char *msg;
94 {
95 fp_query(msg, stdout);
96 }
97
98 /*
99 * Print the contents of a query.
100 * This is intended to be primarily a debugging routine.
101 */
102 void
fp_query(msg,file)103 fp_query(msg, file)
104 char *msg;
105 FILE *file;
106 {
107 register char *cp;
108 register HEADER *hp;
109 register int n;
110
111 /*
112 * Print header fields.
113 */
114 hp = (HEADER *)msg;
115 cp = msg + sizeof (HEADER);
116 fprintf(file, "HEADER:\n");
117 fprintf(file, "\topcode = %s", _res_opcodes[hp->opcode]);
118 fprintf(file, ", id = %d", ntohs(hp->id));
119 fprintf(file, ", rcode = %s\n", _res_resultcodes[hp->rcode]);
120 fprintf(file, "\theader flags: ");
121 if (hp->qr)
122 fprintf(file, " qr");
123 if (hp->aa)
124 fprintf(file, " aa");
125 if (hp->tc)
126 fprintf(file, " tc");
127 if (hp->rd)
128 fprintf(file, " rd");
129 if (hp->ra)
130 fprintf(file, " ra");
131 if (hp->pr)
132 fprintf(file, " pr");
133 fprintf(file, "\n\tqdcount = %d", ntohs(hp->qdcount));
134 fprintf(file, ", ancount = %d", ntohs(hp->ancount));
135 fprintf(file, ", nscount = %d", ntohs(hp->nscount));
136 fprintf(file, ", arcount = %d\n\n", ntohs(hp->arcount));
137 /*
138 * Print question records.
139 */
140 if (n = ntohs(hp->qdcount)) {
141 fprintf(file, "QUESTIONS:\n");
142 while (--n >= 0) {
143 fprintf(file, "\t");
144 cp = p_cdname(cp, msg, file);
145 if (cp == NULL)
146 return;
147 fprintf(file, ", type = %s", p_type(_getshort(cp)));
148 cp += sizeof (u_short);
149 fprintf(file, ", class = %s\n\n",
150 p_class(_getshort(cp)));
151 cp += sizeof (u_short);
152 }
153 }
154 /*
155 * Print authoritative answer records
156 */
157 if (n = ntohs(hp->ancount)) {
158 fprintf(file, "ANSWERS:\n");
159 while (--n >= 0) {
160 fprintf(file, "\t");
161 cp = p_rr(cp, msg, file);
162 if (cp == NULL)
163 return;
164 }
165 }
166 /*
167 * print name server records
168 */
169 if (n = ntohs(hp->nscount)) {
170 fprintf(file, "NAME SERVERS:\n");
171 while (--n >= 0) {
172 fprintf(file, "\t");
173 cp = p_rr(cp, msg, file);
174 if (cp == NULL)
175 return;
176 }
177 }
178 /*
179 * print additional records
180 */
181 if (n = ntohs(hp->arcount)) {
182 fprintf(file, "ADDITIONAL RECORDS:\n");
183 while (--n >= 0) {
184 fprintf(file, "\t");
185 cp = p_rr(cp, msg, file);
186 if (cp == NULL)
187 return;
188 }
189 }
190 }
191
192 char *
p_cdname(cp,msg,file)193 p_cdname(cp, msg, file)
194 char *cp, *msg;
195 FILE *file;
196 {
197 char name[MAXDNAME];
198 int n;
199
200 if ((n = dn_expand((u_char *)msg, (u_char *)(msg + 512), (u_char *)cp,
201 (u_char *)name, sizeof (name))) < 0)
202 return (NULL);
203 if (name[0] == '\0') {
204 name[0] = '.';
205 name[1] = '\0';
206 }
207 fputs(name, file);
208 return (cp + n);
209 }
210
211 /*
212 * Print resource record fields in human readable form.
213 */
214 char *
p_rr(cp,msg,file)215 p_rr(cp, msg, file)
216 char *cp, *msg;
217 FILE *file;
218 {
219 int type, class, dlen, n, c;
220 struct in_addr inaddr;
221 char *cp1, *cp2;
222
223 if ((cp = p_cdname(cp, msg, file)) == NULL)
224 return (NULL); /* compression error */
225 fprintf(file, "\n\ttype = %s", p_type(type = _getshort(cp)));
226 cp += sizeof (u_short);
227 fprintf(file, ", class = %s", p_class(class = _getshort(cp)));
228 cp += sizeof (u_short);
229 fprintf(file, ", ttl = %s", p_time(_getlong(cp)));
230 cp += sizeof (u_long);
231 fprintf(file, ", dlen = %d\n", dlen = _getshort(cp));
232 cp += sizeof (u_short);
233 cp1 = cp;
234 /*
235 * Print type specific data, if appropriate
236 */
237 switch (type) {
238 case T_A:
239 switch (class) {
240 case C_IN:
241 case C_HS:
242 #ifdef SYSV
243 memcpy((void *)&inaddr, (void *)cp, sizeof (inaddr));
244 #else
245 bcopy(cp, (char *)&inaddr, sizeof (inaddr));
246 #endif
247 if (dlen == 4) {
248 fprintf(file, "\tinternet address = %s\n",
249 inet_ntoa(inaddr));
250 cp += dlen;
251 } else if (dlen == 7) {
252 fprintf(file, "\tinternet address = %s",
253 inet_ntoa(inaddr));
254 fprintf(file, ", protocol = %d", cp[4]);
255 fprintf(file, ", port = %d\n",
256 (cp[5] << 8) + cp[6]);
257 cp += dlen;
258 }
259 break;
260 default:
261 cp += dlen;
262 }
263 break;
264 case T_CNAME:
265 case T_MB:
266 case T_MG:
267 case T_MR:
268 case T_NS:
269 case T_PTR:
270 fprintf(file, "\tdomain name = ");
271 cp = p_cdname(cp, msg, file);
272 fprintf(file, "\n");
273 break;
274
275 case T_HINFO:
276 if (n = *cp++) {
277 fprintf(file, "\tCPU=%.*s\n", n, cp);
278 cp += n;
279 }
280 if (n = *cp++) {
281 fprintf(file, "\tOS=%.*s\n", n, cp);
282 cp += n;
283 }
284 break;
285
286 case T_SOA:
287 fprintf(file, "\torigin = ");
288 cp = p_cdname(cp, msg, file);
289 fprintf(file, "\n\tmail addr = ");
290 cp = p_cdname(cp, msg, file);
291 fprintf(file, "\n\tserial = %ld", _getlong(cp));
292 cp += sizeof (u_long);
293 fprintf(file, "\n\trefresh = %s", p_time(_getlong(cp)));
294 cp += sizeof (u_long);
295 fprintf(file, "\n\tretry = %s", p_time(_getlong(cp)));
296 cp += sizeof (u_long);
297 fprintf(file, "\n\texpire = %s", p_time(_getlong(cp)));
298 cp += sizeof (u_long);
299 fprintf(file, "\n\tmin = %s\n", p_time(_getlong(cp)));
300 cp += sizeof (u_long);
301 break;
302
303 case T_MX:
304 fprintf(file, "\tpreference = %ld,", _getshort(cp));
305 cp += sizeof (u_short);
306 fprintf(file, " name = ");
307 cp = p_cdname(cp, msg, file);
308 break;
309
310 case T_TXT:
311 (void) fputs("\t\"", file);
312 cp2 = cp1 + dlen;
313 while (cp < cp2) {
314 if (n = (unsigned char) *cp++) {
315 for (c = n; c > 0 && cp < cp2; c--)
316 if (*cp == '\n') {
317 (void) putc('\\', file);
318 (void) putc(*cp++, file);
319 } else
320 (void) putc(*cp++, file);
321 }
322 }
323 (void) fputs("\"\n", file);
324 break;
325
326 case T_MINFO:
327 fprintf(file, "\trequests = ");
328 cp = p_cdname(cp, msg, file);
329 fprintf(file, "\n\terrors = ");
330 cp = p_cdname(cp, msg, file);
331 break;
332
333 case T_UINFO:
334 fprintf(file, "\t%s\n", cp);
335 cp += dlen;
336 break;
337
338 case T_UID:
339 case T_GID:
340 if (dlen == 4) {
341 fprintf(file, "\t%ld\n", _getlong(cp));
342 cp += sizeof (int);
343 }
344 break;
345
346 case T_WKS:
347 if (dlen < sizeof (u_long) + 1)
348 break;
349 #ifdef SYSV
350 memcpy((void *)&inaddr, (void *)cp, sizeof (inaddr));
351 #else
352 bcopy(cp, (char *)&inaddr, sizeof (inaddr));
353 #endif
354 cp += sizeof (u_long);
355 fprintf(file, "\tinternet address = %s, protocol = %d\n\t",
356 inet_ntoa(inaddr), *cp++);
357 n = 0;
358 while (cp < cp1 + dlen) {
359 c = *cp++;
360 do {
361 if (c & 0200)
362 fprintf(file, " %d", n);
363 c <<= 1;
364 } while (++n & 07);
365 }
366 putc('\n', file);
367 break;
368
369 #ifdef ALLOW_T_UNSPEC
370 case T_UNSPEC:
371 {
372 int NumBytes = 8;
373 char *DataPtr;
374 int i;
375
376 if (dlen < NumBytes) NumBytes = dlen;
377 fprintf(file, "\tFirst %d bytes of hex data:",
378 NumBytes);
379 for (i = 0, DataPtr = cp; i < NumBytes; i++, DataPtr++)
380 fprintf(file, " %x", *DataPtr);
381 fputs("\n", file);
382 cp += dlen;
383 }
384 break;
385 #endif /* ALLOW_T_UNSPEC */
386
387 default:
388 fprintf(file, "\t???\n");
389 cp += dlen;
390 }
391 if (cp != cp1 + dlen) {
392 fprintf(file, "packet size error (%#x != %#x)\n", cp, cp1+dlen);
393 cp = NULL;
394 }
395 fprintf(file, "\n");
396 return (cp);
397 }
398
399 static char nbuf[40];
400
401 /*
402 * Return a string for the type
403 */
404 char *
p_type(type)405 p_type(type)
406 int type;
407 {
408 switch (type) {
409 case T_A:
410 return ("A");
411 case T_NS: /* authoritative server */
412 return ("NS");
413 case T_CNAME: /* canonical name */
414 return ("CNAME");
415 case T_SOA: /* start of authority zone */
416 return ("SOA");
417 case T_MB: /* mailbox domain name */
418 return ("MB");
419 case T_MG: /* mail group member */
420 return ("MG");
421 case T_MR: /* mail rename name */
422 return ("MR");
423 case T_NULL: /* null resource record */
424 return ("NULL");
425 case T_WKS: /* well known service */
426 return ("WKS");
427 case T_PTR: /* domain name pointer */
428 return ("PTR");
429 case T_HINFO: /* host information */
430 return ("HINFO");
431 case T_MINFO: /* mailbox information */
432 return ("MINFO");
433 case T_MX: /* mail routing info */
434 return ("MX");
435 case T_TXT: /* text */
436 return ("TXT");
437 case T_AXFR: /* zone transfer */
438 return ("AXFR");
439 case T_MAILB: /* mail box */
440 return ("MAILB");
441 case T_MAILA: /* mail address */
442 return ("MAILA");
443 case T_ANY: /* matches any type */
444 return ("ANY");
445 case T_UINFO:
446 return ("UINFO");
447 case T_UID:
448 return ("UID");
449 case T_GID:
450 return ("GID");
451 #ifdef ALLOW_T_UNSPEC
452 case T_UNSPEC:
453 return ("UNSPEC");
454 #endif /* ALLOW_T_UNSPEC */
455 default:
456 (void) sprintf(nbuf, "%d", type);
457 return (nbuf);
458 }
459 }
460
461 /*
462 * Return a mnemonic for class
463 */
464 char *
p_class(class)465 p_class(class)
466 int class;
467 {
468
469 switch (class) {
470 case C_IN: /* internet class */
471 return ("IN");
472 case C_HS: /* hesiod class */
473 return ("HS");
474 case C_ANY: /* matches any class */
475 return ("ANY");
476 default:
477 (void) sprintf(nbuf, "%d", class);
478 return (nbuf);
479 }
480 }
481
482 /*
483 * Return a mnemonic for a time to live
484 */
485 char *
p_time(value)486 p_time(value)
487 u_long value;
488 {
489 int secs, mins, hours;
490 register char *p;
491
492 if (value == 0) {
493 strcpy(nbuf, "0 secs");
494 return (nbuf);
495 }
496
497 secs = value % 60;
498 value /= 60;
499 mins = value % 60;
500 value /= 60;
501 hours = value % 24;
502 value /= 24;
503
504 #define PLURALIZE(x) x, (x == 1) ? "" : "s"
505 p = nbuf;
506 if (value) {
507 (void) sprintf(p, "%d day%s", PLURALIZE(value));
508 while (*++p);
509 }
510 if (hours) {
511 if (value)
512 *p++ = ' ';
513 (void) sprintf(p, "%d hour%s", PLURALIZE(hours));
514 while (*++p);
515 }
516 if (mins) {
517 if (value || hours)
518 *p++ = ' ';
519 (void) sprintf(p, "%d min%s", PLURALIZE(mins));
520 while (*++p);
521 }
522 if (secs || ! (value || hours || mins)) {
523 if (value || hours || mins)
524 *p++ = ' ';
525 (void) sprintf(p, "%d sec%s", PLURALIZE(secs));
526 }
527 return (nbuf);
528 }
529