| 1 | /* |
| 2 | * Copyright (c) 1985 Regents of the University of California. |
| 3 | * All rights reserved. The Berkeley software License Agreement |
| 4 | * specifies the terms and conditions for redistribution. |
| 5 | */ |
| 6 | |
| 7 | #if defined(LIBC_SCCS) && !defined(lint) |
| 8 | static char sccsid[] = "@(#)res_debug.c 5.19 (Berkeley) %G%"; |
| 9 | #endif LIBC_SCCS and not lint |
| 10 | |
| 11 | #if defined(lint) && !defined(DEBUG) |
| 12 | #define DEBUG |
| 13 | #endif |
| 14 | |
| 15 | #include <sys/types.h> |
| 16 | #include <netinet/in.h> |
| 17 | #include <stdio.h> |
| 18 | #include <arpa/nameser.h> |
| 19 | |
| 20 | extern char *p_cdname(), *p_rr(), *p_type(), *p_class(); |
| 21 | extern char *inet_ntoa(); |
| 22 | |
| 23 | char *_res_opcodes[] = { |
| 24 | "QUERY", |
| 25 | "IQUERY", |
| 26 | "CQUERYM", |
| 27 | "CQUERYU", |
| 28 | "4", |
| 29 | "5", |
| 30 | "6", |
| 31 | "7", |
| 32 | "8", |
| 33 | "UPDATEA", |
| 34 | "UPDATED", |
| 35 | "UPDATEDA", |
| 36 | "UPDATEM", |
| 37 | "UPDATEMA", |
| 38 | "ZONEINIT", |
| 39 | "ZONEREF", |
| 40 | }; |
| 41 | |
| 42 | char *_res_resultcodes[] = { |
| 43 | "NOERROR", |
| 44 | "FORMERR", |
| 45 | "SERVFAIL", |
| 46 | "NXDOMAIN", |
| 47 | "NOTIMP", |
| 48 | "REFUSED", |
| 49 | "6", |
| 50 | "7", |
| 51 | "8", |
| 52 | "9", |
| 53 | "10", |
| 54 | "11", |
| 55 | "12", |
| 56 | "13", |
| 57 | "14", |
| 58 | "NOCHANGE", |
| 59 | }; |
| 60 | |
| 61 | p_query(msg) |
| 62 | char *msg; |
| 63 | { |
| 64 | #ifdef DEBUG |
| 65 | fp_query(msg,stdout); |
| 66 | #endif |
| 67 | } |
| 68 | |
| 69 | /* |
| 70 | * Print the contents of a query. |
| 71 | * This is intended to be primarily a debugging routine. |
| 72 | */ |
| 73 | fp_query(msg,file) |
| 74 | char *msg; |
| 75 | FILE *file; |
| 76 | { |
| 77 | #ifdef DEBUG |
| 78 | register char *cp; |
| 79 | register HEADER *hp; |
| 80 | register int n; |
| 81 | |
| 82 | /* |
| 83 | * Print header fields. |
| 84 | */ |
| 85 | hp = (HEADER *)msg; |
| 86 | cp = msg + sizeof(HEADER); |
| 87 | fprintf(file,"HEADER:\n"); |
| 88 | fprintf(file,"\topcode = %s", _opcodes[hp->opcode]); |
| 89 | fprintf(file,", id = %d", ntohs(hp->id)); |
| 90 | fprintf(file,", rcode = %s\n", _rcodes[hp->rcode]); |
| 91 | fprintf(file,"\theader flags: "); |
| 92 | if (hp->qr) |
| 93 | fprintf(file," qr"); |
| 94 | if (hp->aa) |
| 95 | fprintf(file," aa"); |
| 96 | if (hp->tc) |
| 97 | fprintf(file," tc"); |
| 98 | if (hp->rd) |
| 99 | fprintf(file," rd"); |
| 100 | if (hp->ra) |
| 101 | fprintf(file," ra"); |
| 102 | if (hp->pr) |
| 103 | fprintf(file," pr"); |
| 104 | fprintf(file,"\n\tqdcount = %d", ntohs(hp->qdcount)); |
| 105 | fprintf(file,", ancount = %d", ntohs(hp->ancount)); |
| 106 | fprintf(file,", nscount = %d", ntohs(hp->nscount)); |
| 107 | fprintf(file,", arcount = %d\n\n", ntohs(hp->arcount)); |
| 108 | /* |
| 109 | * Print question records. |
| 110 | */ |
| 111 | if (n = ntohs(hp->qdcount)) { |
| 112 | fprintf(file,"QUESTIONS:\n"); |
| 113 | while (--n >= 0) { |
| 114 | fprintf(file,"\t"); |
| 115 | cp = p_cdname(cp, msg, file); |
| 116 | if (cp == NULL) |
| 117 | return; |
| 118 | fprintf(file,", type = %s", p_type(_getshort(cp))); |
| 119 | cp += sizeof(u_short); |
| 120 | fprintf(file,", class = %s\n\n", p_class(_getshort(cp))); |
| 121 | cp += sizeof(u_short); |
| 122 | } |
| 123 | } |
| 124 | /* |
| 125 | * Print authoritative answer records |
| 126 | */ |
| 127 | if (n = ntohs(hp->ancount)) { |
| 128 | fprintf(file,"ANSWERS:\n"); |
| 129 | while (--n >= 0) { |
| 130 | fprintf(file,"\t"); |
| 131 | cp = p_rr(cp, msg, file); |
| 132 | if (cp == NULL) |
| 133 | return; |
| 134 | } |
| 135 | } |
| 136 | /* |
| 137 | * print name server records |
| 138 | */ |
| 139 | if (n = ntohs(hp->nscount)) { |
| 140 | fprintf(file,"NAME SERVERS:\n"); |
| 141 | while (--n >= 0) { |
| 142 | fprintf(file,"\t"); |
| 143 | cp = p_rr(cp, msg, file); |
| 144 | if (cp == NULL) |
| 145 | return; |
| 146 | } |
| 147 | } |
| 148 | /* |
| 149 | * print additional records |
| 150 | */ |
| 151 | if (n = ntohs(hp->arcount)) { |
| 152 | fprintf(file,"ADDITIONAL RECORDS:\n"); |
| 153 | while (--n >= 0) { |
| 154 | fprintf(file,"\t"); |
| 155 | cp = p_rr(cp, msg, file); |
| 156 | if (cp == NULL) |
| 157 | return; |
| 158 | } |
| 159 | } |
| 160 | #endif |
| 161 | } |
| 162 | |
| 163 | char * |
| 164 | p_cdname(cp, msg, file) |
| 165 | char *cp, *msg; |
| 166 | FILE *file; |
| 167 | { |
| 168 | #ifdef DEBUG |
| 169 | char name[MAXDNAME]; |
| 170 | int n; |
| 171 | |
| 172 | if ((n = dn_expand(msg, msg + 512, cp, name, sizeof(name))) < 0) |
| 173 | return (NULL); |
| 174 | if (name[0] == '\0') { |
| 175 | name[0] = '.'; |
| 176 | name[1] = '\0'; |
| 177 | } |
| 178 | fputs(name, file); |
| 179 | return (cp + n); |
| 180 | #endif |
| 181 | } |
| 182 | |
| 183 | /* |
| 184 | * Print resource record fields in human readable form. |
| 185 | */ |
| 186 | char * |
| 187 | p_rr(cp, msg, file) |
| 188 | char *cp, *msg; |
| 189 | FILE *file; |
| 190 | { |
| 191 | #ifdef DEBUG |
| 192 | int type, class, dlen, n, c; |
| 193 | struct in_addr inaddr; |
| 194 | char *cp1; |
| 195 | |
| 196 | if ((cp = p_cdname(cp, msg, file)) == NULL) |
| 197 | return (NULL); /* compression error */ |
| 198 | fprintf(file,"\n\ttype = %s", p_type(type = _getshort(cp))); |
| 199 | cp += sizeof(u_short); |
| 200 | fprintf(file,", class = %s", p_class(class = _getshort(cp))); |
| 201 | cp += sizeof(u_short); |
| 202 | fprintf(file,", ttl = %u", _getlong(cp)); |
| 203 | cp += sizeof(u_long); |
| 204 | fprintf(file,", dlen = %d\n", dlen = _getshort(cp)); |
| 205 | cp += sizeof(u_short); |
| 206 | cp1 = cp; |
| 207 | /* |
| 208 | * Print type specific data, if appropriate |
| 209 | */ |
| 210 | switch (type) { |
| 211 | case T_A: |
| 212 | switch (class) { |
| 213 | case C_IN: |
| 214 | bcopy(cp, (char *)&inaddr, sizeof(inaddr)); |
| 215 | if (dlen == 4) { |
| 216 | fprintf(file,"\tinternet address = %s\n", |
| 217 | inet_ntoa(inaddr)); |
| 218 | cp += dlen; |
| 219 | } else if (dlen == 7) { |
| 220 | fprintf(file,"\tinternet address = %s", |
| 221 | inet_ntoa(inaddr)); |
| 222 | fprintf(file,", protocol = %d", cp[4]); |
| 223 | fprintf(file,", port = %d\n", |
| 224 | (cp[5] << 8) + cp[6]); |
| 225 | cp += dlen; |
| 226 | } |
| 227 | break; |
| 228 | default: |
| 229 | cp += dlen; |
| 230 | } |
| 231 | break; |
| 232 | case T_CNAME: |
| 233 | case T_MB: |
| 234 | #ifdef OLDRR |
| 235 | case T_MD: |
| 236 | case T_MF: |
| 237 | #endif /* OLDRR */ |
| 238 | case T_MG: |
| 239 | case T_MR: |
| 240 | case T_NS: |
| 241 | case T_PTR: |
| 242 | fprintf(file,"\tdomain name = "); |
| 243 | cp = p_cdname(cp, msg, file); |
| 244 | fprintf(file,"\n"); |
| 245 | break; |
| 246 | |
| 247 | case T_HINFO: |
| 248 | if (n = *cp++) { |
| 249 | fprintf(file,"\tCPU=%.*s\n", n, cp); |
| 250 | cp += n; |
| 251 | } |
| 252 | if (n = *cp++) { |
| 253 | fprintf(file,"\tOS=%.*s\n", n, cp); |
| 254 | cp += n; |
| 255 | } |
| 256 | break; |
| 257 | |
| 258 | case T_SOA: |
| 259 | fprintf(file,"\torigin = "); |
| 260 | cp = p_cdname(cp, msg, file); |
| 261 | fprintf(file,"\n\tmail addr = "); |
| 262 | cp = p_cdname(cp, msg, file); |
| 263 | fprintf(file,"\n\tserial=%ld", _getlong(cp)); |
| 264 | cp += sizeof(u_long); |
| 265 | fprintf(file,", refresh=%ld", _getlong(cp)); |
| 266 | cp += sizeof(u_long); |
| 267 | fprintf(file,", retry=%ld", _getlong(cp)); |
| 268 | cp += sizeof(u_long); |
| 269 | fprintf(file,", expire=%ld", _getlong(cp)); |
| 270 | cp += sizeof(u_long); |
| 271 | fprintf(file,", min=%ld\n", _getlong(cp)); |
| 272 | cp += sizeof(u_long); |
| 273 | break; |
| 274 | |
| 275 | case T_MX: |
| 276 | fprintf(file,"\tpreference = %ld,",_getshort(cp)); |
| 277 | cp += sizeof(u_short); |
| 278 | fprintf(file," name = "); |
| 279 | cp = p_cdname(cp, msg, file); |
| 280 | break; |
| 281 | |
| 282 | case T_MINFO: |
| 283 | fprintf(file,"\trequests = "); |
| 284 | cp = p_cdname(cp, msg, file); |
| 285 | fprintf(file,"\n\terrors = "); |
| 286 | cp = p_cdname(cp, msg, file); |
| 287 | break; |
| 288 | |
| 289 | case T_UINFO: |
| 290 | fprintf(file,"\t%s\n", cp); |
| 291 | cp += dlen; |
| 292 | break; |
| 293 | |
| 294 | case T_UID: |
| 295 | case T_GID: |
| 296 | if (dlen == 4) { |
| 297 | fprintf(file,"\t%ld\n", _getlong(cp)); |
| 298 | cp += sizeof(int); |
| 299 | } |
| 300 | break; |
| 301 | |
| 302 | case T_WKS: |
| 303 | if (dlen < sizeof(u_long) + 1) |
| 304 | break; |
| 305 | bcopy(cp, (char *)&inaddr, sizeof(inaddr)); |
| 306 | cp += sizeof(u_long); |
| 307 | fprintf(file,"\tinternet address = %s, protocol = %d\n\t", |
| 308 | inet_ntoa(inaddr), *cp++); |
| 309 | n = 0; |
| 310 | while (cp < cp1 + dlen) { |
| 311 | c = *cp++; |
| 312 | do { |
| 313 | if (c & 0200) |
| 314 | fprintf(file," %d", n); |
| 315 | c <<= 1; |
| 316 | } while (++n & 07); |
| 317 | } |
| 318 | putc('\n',file); |
| 319 | break; |
| 320 | |
| 321 | #ifdef ALLOW_T_UNSPEC |
| 322 | case T_UNSPEC: |
| 323 | { |
| 324 | int NumBytes = 8; |
| 325 | char *DataPtr; |
| 326 | int i; |
| 327 | |
| 328 | if (dlen < NumBytes) NumBytes = dlen; |
| 329 | fprintf(file, "\tFirst %d bytes of hex data:", |
| 330 | NumBytes); |
| 331 | for (i = 0, DataPtr = cp; i < NumBytes; i++, DataPtr++) |
| 332 | fprintf(file, " %x", *DataPtr); |
| 333 | fputs("\n", file); |
| 334 | cp += dlen; |
| 335 | } |
| 336 | break; |
| 337 | #endif /* ALLOW_T_UNSPEC */ |
| 338 | |
| 339 | default: |
| 340 | fprintf(file,"\t???\n"); |
| 341 | cp += dlen; |
| 342 | } |
| 343 | if (cp != cp1 + dlen) |
| 344 | fprintf(file,"packet size error (%#x != %#x)\n", cp, cp1+dlen); |
| 345 | fprintf(file,"\n"); |
| 346 | return (cp); |
| 347 | #endif |
| 348 | } |
| 349 | |
| 350 | static char nbuf[20]; |
| 351 | extern char *sprintf(); |
| 352 | |
| 353 | /* |
| 354 | * Return a string for the type |
| 355 | */ |
| 356 | char * |
| 357 | p_type(type) |
| 358 | int type; |
| 359 | { |
| 360 | switch (type) { |
| 361 | case T_A: |
| 362 | return("A"); |
| 363 | case T_NS: /* authoritative server */ |
| 364 | return("NS"); |
| 365 | #ifdef OLDRR |
| 366 | case T_MD: /* mail destination */ |
| 367 | return("MD"); |
| 368 | case T_MF: /* mail forwarder */ |
| 369 | return("MF"); |
| 370 | #endif /* OLDRR */ |
| 371 | case T_CNAME: /* connonical name */ |
| 372 | return("CNAME"); |
| 373 | case T_SOA: /* start of authority zone */ |
| 374 | return("SOA"); |
| 375 | case T_MB: /* mailbox domain name */ |
| 376 | return("MB"); |
| 377 | case T_MG: /* mail group member */ |
| 378 | return("MG"); |
| 379 | case T_MX: /* mail routing info */ |
| 380 | return("MX"); |
| 381 | case T_MR: /* mail rename name */ |
| 382 | return("MR"); |
| 383 | case T_NULL: /* null resource record */ |
| 384 | return("NULL"); |
| 385 | case T_WKS: /* well known service */ |
| 386 | return("WKS"); |
| 387 | case T_PTR: /* domain name pointer */ |
| 388 | return("PTR"); |
| 389 | case T_HINFO: /* host information */ |
| 390 | return("HINFO"); |
| 391 | case T_MINFO: /* mailbox information */ |
| 392 | return("MINFO"); |
| 393 | case T_AXFR: /* zone transfer */ |
| 394 | return("AXFR"); |
| 395 | case T_MAILB: /* mail box */ |
| 396 | return("MAILB"); |
| 397 | case T_MAILA: /* mail address */ |
| 398 | return("MAILA"); |
| 399 | case T_ANY: /* matches any type */ |
| 400 | return("ANY"); |
| 401 | case T_UINFO: |
| 402 | return("UINFO"); |
| 403 | case T_UID: |
| 404 | return("UID"); |
| 405 | case T_GID: |
| 406 | return("GID"); |
| 407 | #ifdef ALLOW_T_UNSPEC |
| 408 | case T_UNSPEC: |
| 409 | return("UNSPEC"); |
| 410 | #endif /* ALLOW_T_UNSPEC */ |
| 411 | default: |
| 412 | return (sprintf(nbuf, "%d", type)); |
| 413 | } |
| 414 | } |
| 415 | |
| 416 | /* |
| 417 | * Return a mnemonic for class |
| 418 | */ |
| 419 | char * |
| 420 | p_class(class) |
| 421 | int class; |
| 422 | { |
| 423 | |
| 424 | switch (class) { |
| 425 | case C_IN: /* internet class */ |
| 426 | return("IN"); |
| 427 | case C_ANY: /* matches any class */ |
| 428 | return("ANY"); |
| 429 | default: |
| 430 | return (sprintf(nbuf, "%d", class)); |
| 431 | } |
| 432 | } |