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