]>
Commit | Line | Data |
---|---|---|
461eef68 | 1 | |
7f3647d6 | 2 | /* |
d0017a72 | 3 | * $Id: rfc1035.c,v 1.13 2000/02/01 05:15:26 wessels Exp $ |
7f3647d6 | 4 | * |
5 | * Low level DNS protocol routines | |
6 | * AUTHOR: Duane Wessels | |
7 | * | |
8 | * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ | |
9 | * ---------------------------------------------------------- | |
10 | * | |
11 | * Squid is the result of efforts by numerous individuals from the | |
12 | * Internet community. Development is led by Duane Wessels of the | |
13 | * National Laboratory for Applied Network Research and funded by the | |
14 | * National Science Foundation. Squid is Copyrighted (C) 1998 by | |
15 | * Duane Wessels and the University of California San Diego. Please | |
16 | * see the COPYRIGHT file for full details. Squid incorporates | |
17 | * software developed and/or copyrighted by other sources. Please see | |
18 | * the CREDITS file for full details. | |
19 | * | |
20 | * This program is free software; you can redistribute it and/or modify | |
21 | * it under the terms of the GNU General Public License as published by | |
22 | * the Free Software Foundation; either version 2 of the License, or | |
23 | * (at your option) any later version. | |
24 | * | |
25 | * This program is distributed in the hope that it will be useful, | |
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
28 | * GNU General Public License for more details. | |
29 | * | |
30 | * You should have received a copy of the GNU General Public License | |
31 | * along with this program; if not, write to the Free Software | |
32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. | |
33 | * | |
34 | */ | |
35 | ||
fb29421b | 36 | #include "config.h" |
37 | ||
38 | #if HAVE_STDIO_H | |
39 | #include <stdio.h> | |
40 | #endif | |
41 | #if HAVE_UNISTD_H | |
42 | #include <unistd.h> | |
43 | #endif | |
44 | #if HAVE_STDLIB_H | |
45 | #include <stdlib.h> | |
46 | #endif | |
47 | #if HAVE_MEMORY_H | |
48 | #include <memory.h> | |
49 | #endif | |
50 | #if HAVE_SYS_TYPES_H | |
51 | #include <sys/types.h> | |
52 | #endif | |
53 | #if HAVE_ASSERT_H | |
54 | #include <assert.h> | |
55 | #endif | |
56 | #if HAVE_NETINET_IN_H | |
57 | #include <netinet/in.h> | |
58 | #endif | |
59 | #if HAVE_ARPA_INET_H | |
60 | #include <arpa/inet.h> | |
61 | #endif | |
62 | #if HAVE_STRINGS_H | |
63 | #include <strings.h> | |
64 | #endif | |
65 | ||
7b724b86 | 66 | #include "rfc1035.h" |
d86af726 | 67 | #include "snprintf.h" |
fb29421b | 68 | |
69 | #define RFC1035_MAXLABELSZ 63 | |
fb29421b | 70 | |
7b724b86 | 71 | typedef struct _rfc1035_header rfc1035_header; |
fb29421b | 72 | |
73 | int rfc1035_errno; | |
7b724b86 | 74 | const char *rfc1035_error_message; |
75 | struct _rfc1035_header { | |
fb29421b | 76 | unsigned short id; |
77 | unsigned int qr:1; | |
78 | unsigned int opcode:4; | |
79 | unsigned int aa:1; | |
80 | unsigned int tc:1; | |
81 | unsigned int rd:1; | |
82 | unsigned int ra:1; | |
83 | unsigned int rcode:4; | |
84 | unsigned short qdcount; | |
85 | unsigned short ancount; | |
86 | unsigned short nscount; | |
87 | unsigned short arcount; | |
88 | }; | |
89 | ||
fb29421b | 90 | /* |
91 | * rfc1035HeaderPack() | |
92 | * | |
7b724b86 | 93 | * Packs a rfc1035_header structure into a buffer. |
fb29421b | 94 | * Returns number of octets packed (should always be 12) |
95 | */ | |
96 | static off_t | |
7b724b86 | 97 | rfc1035HeaderPack(char *buf, size_t sz, rfc1035_header * hdr) |
fb29421b | 98 | { |
99 | off_t off = 0; | |
100 | unsigned short s; | |
101 | unsigned short t; | |
102 | assert(sz >= 12); | |
103 | s = htons(hdr->id); | |
104 | memcpy(buf + off, &s, sizeof(s)); | |
105 | off += sizeof(s); | |
106 | t = 0; | |
107 | t |= hdr->qr << 15; | |
108 | t |= (hdr->opcode << 11); | |
109 | t |= (hdr->aa << 10); | |
110 | t |= (hdr->tc << 9); | |
111 | t |= (hdr->rd << 8); | |
112 | t |= (hdr->ra << 7); | |
113 | t |= hdr->rcode; | |
114 | s = htons(t); | |
115 | memcpy(buf + off, &s, sizeof(s)); | |
116 | off += sizeof(s); | |
117 | s = htons(hdr->qdcount); | |
118 | memcpy(buf + off, &s, sizeof(s)); | |
119 | off += sizeof(s); | |
120 | s = htons(hdr->ancount); | |
121 | memcpy(buf + off, &s, sizeof(s)); | |
122 | off += sizeof(s); | |
123 | s = htons(hdr->nscount); | |
124 | memcpy(buf + off, &s, sizeof(s)); | |
125 | off += sizeof(s); | |
126 | s = htons(hdr->arcount); | |
127 | memcpy(buf + off, &s, sizeof(s)); | |
128 | off += sizeof(s); | |
129 | assert(off == 12); | |
130 | return off; | |
131 | } | |
132 | ||
133 | /* | |
134 | * rfc1035LabelPack() | |
135 | * | |
136 | * Packs a label into a buffer. The format of | |
137 | * a label is one octet specifying the number of character | |
138 | * bytes to follow. Labels must be smaller than 64 octets. | |
139 | * Returns number of octets packed. | |
140 | */ | |
141 | static off_t | |
142 | rfc1035LabelPack(char *buf, size_t sz, const char *label) | |
143 | { | |
144 | off_t off = 0; | |
145 | size_t len = label ? strlen(label) : 0; | |
146 | if (label) | |
147 | assert(!strchr(label, '.')); | |
148 | if (len > RFC1035_MAXLABELSZ) | |
149 | len = RFC1035_MAXLABELSZ; | |
150 | assert(sz >= len + 1); | |
151 | *(buf + off) = (char) len; | |
152 | off++; | |
153 | memcpy(buf + off, label, len); | |
154 | off += len; | |
155 | return off; | |
156 | } | |
157 | ||
158 | /* | |
159 | * rfc1035NamePack() | |
160 | * | |
161 | * Packs a name into a buffer. Names are packed as a | |
162 | * sequence of labels, terminated with NULL label. | |
163 | * Note message compression is not supported here. | |
164 | * Returns number of octets packed. | |
165 | */ | |
166 | off_t | |
167 | rfc1035NamePack(char *buf, size_t sz, const char *name) | |
168 | { | |
169 | off_t off = 0; | |
170 | char *copy = strdup(name); | |
171 | char *t; | |
172 | for (t = strtok(copy, "."); t; t = strtok(NULL, ".")) | |
173 | off += rfc1035LabelPack(buf + off, sz - off, t); | |
174 | free(copy); | |
175 | off += rfc1035LabelPack(buf + off, sz - off, NULL); | |
176 | assert(off <= sz); | |
177 | return off; | |
178 | } | |
179 | ||
180 | /* | |
181 | * rfc1035QuestionPack() | |
182 | * | |
183 | * Packs a QUESTION section of a message. | |
184 | * Returns number of octets packed. | |
185 | */ | |
186 | static off_t | |
187 | rfc1035QuestionPack(char *buf, | |
188 | size_t sz, | |
189 | const char *name, | |
190 | unsigned short type, | |
191 | unsigned short class) | |
192 | { | |
193 | off_t off = 0; | |
194 | unsigned short s; | |
195 | off += rfc1035NamePack(buf + off, sz - off, name); | |
196 | s = htons(type); | |
197 | memcpy(buf + off, &s, sizeof(s)); | |
198 | off += sizeof(s); | |
199 | s = htons(class); | |
200 | memcpy(buf + off, &s, sizeof(s)); | |
201 | off += sizeof(s); | |
202 | assert(off <= sz); | |
203 | return off; | |
204 | } | |
205 | ||
206 | /* | |
207 | * rfc1035HeaderUnpack() | |
208 | * | |
7b724b86 | 209 | * Unpacks a RFC1035 message header buffer into a rfc1035_header |
fb29421b | 210 | * structure. |
211 | * Returns the new buffer offset, which is the same as number of | |
212 | * octects unpacked since the header starts at offset 0. | |
213 | */ | |
214 | static off_t | |
7b724b86 | 215 | rfc1035HeaderUnpack(const char *buf, size_t sz, rfc1035_header * h) |
fb29421b | 216 | { |
217 | unsigned short s; | |
218 | unsigned short t; | |
219 | off_t off = 0; | |
220 | assert(sz >= 12); | |
221 | memcpy(&s, buf + off, sizeof(s)); | |
222 | off += sizeof(s); | |
223 | h->id = ntohs(s); | |
224 | memcpy(&s, buf + off, sizeof(s)); | |
225 | off += sizeof(s); | |
226 | t = ntohs(s); | |
227 | h->qr = (t >> 15) & 0x01; | |
228 | h->opcode = (t >> 11) & 0x0F; | |
229 | h->aa = (t >> 10) & 0x01; | |
230 | h->tc = (t >> 8) & 0x01; | |
231 | h->rd = (t >> 8) & 0x01; | |
232 | h->ra = (t >> 7) & 0x01; | |
233 | h->rcode = t & 0x0F; | |
234 | memcpy(&s, buf + off, sizeof(s)); | |
235 | off += sizeof(s); | |
236 | h->qdcount = ntohs(s); | |
237 | memcpy(&s, buf + off, sizeof(s)); | |
238 | off += sizeof(s); | |
239 | h->ancount = ntohs(s); | |
240 | memcpy(&s, buf + off, sizeof(s)); | |
241 | off += sizeof(s); | |
242 | h->nscount = ntohs(s); | |
243 | memcpy(&s, buf + off, sizeof(s)); | |
244 | off += sizeof(s); | |
245 | h->arcount = ntohs(s); | |
246 | assert(off == 12); | |
247 | return off; | |
248 | } | |
249 | ||
250 | /* | |
251 | * rfc1035NameUnpack() | |
252 | * | |
253 | * Unpacks a Name in a message buffer into a char*. | |
254 | * Note 'buf' points to the beginning of the whole message, | |
255 | * 'off' points to the spot where the Name begins, and 'sz' | |
256 | * is the size of the whole message. 'name' must be allocated | |
257 | * by the caller. | |
258 | * | |
259 | * Supports the RFC1035 message compression through recursion. | |
260 | * | |
261 | * Returns the new buffer offset. | |
262 | */ | |
263 | static off_t | |
264 | rfc1035NameUnpack(const char *buf, size_t sz, off_t off, char *name, size_t ns) | |
265 | { | |
266 | off_t no = 0; | |
267 | unsigned char c; | |
268 | size_t len; | |
269 | assert(ns > 0); | |
270 | do { | |
271 | c = *(buf + off); | |
272 | if (c > RFC1035_MAXLABELSZ) { | |
c4eb7525 | 273 | /* blasted compression */ |
fb29421b | 274 | unsigned short s; |
275 | off_t ptr; | |
276 | memcpy(&s, buf + off, sizeof(s)); | |
277 | s = ntohs(s); | |
278 | off += sizeof(s); | |
279 | ptr = s & 0x3FFF; | |
280 | (void) rfc1035NameUnpack(buf, sz, ptr, name + no, ns - no); | |
281 | return off; | |
282 | } else { | |
283 | off++; | |
284 | len = (size_t) c; | |
285 | if (len == 0) | |
286 | break; | |
7b724b86 | 287 | if (len > (ns - 1)) |
288 | len = ns - 1; | |
fb29421b | 289 | memcpy(name + no, buf + off, len); |
290 | off += len; | |
291 | no += len; | |
292 | *(name + (no++)) = '.'; | |
293 | } | |
294 | } while (c > 0); | |
295 | *(name + no - 1) = '\0'; | |
296 | assert(no <= ns); | |
297 | return off; | |
298 | } | |
299 | ||
300 | /* | |
301 | * rfc1035RRUnpack() | |
302 | * | |
303 | * Unpacks a RFC1035 Resource Record into 'RR' from a message buffer. | |
304 | * The caller must free RR->rdata! | |
305 | * Returns the new message buffer offset. | |
306 | */ | |
307 | static off_t | |
7b724b86 | 308 | rfc1035RRUnpack(const char *buf, size_t sz, off_t off, rfc1035_rr * RR) |
fb29421b | 309 | { |
310 | unsigned short s; | |
311 | unsigned int i; | |
312 | off = rfc1035NameUnpack(buf, sz, off, RR->name, RFC1035_MAXHOSTNAMESZ); | |
313 | memcpy(&s, buf + off, sizeof(s)); | |
314 | off += sizeof(s); | |
315 | RR->type = ntohs(s); | |
316 | memcpy(&s, buf + off, sizeof(s)); | |
317 | off += sizeof(s); | |
318 | RR->class = ntohs(s); | |
319 | memcpy(&i, buf + off, sizeof(i)); | |
320 | off += sizeof(i); | |
321 | RR->ttl = ntohl(i); | |
322 | memcpy(&s, buf + off, sizeof(s)); | |
323 | off += sizeof(s); | |
b8cbc836 | 324 | switch (RR->type) { |
325 | case RFC1035_TYPE_PTR: | |
326 | RR->rdata = malloc(RFC1035_MAXHOSTNAMESZ); | |
327 | rfc1035NameUnpack(buf, sz, off, RR->rdata, RFC1035_MAXHOSTNAMESZ); | |
328 | RR->rdlength = strlen(RR->rdata); | |
329 | break; | |
330 | case RFC1035_TYPE_A: | |
331 | default: | |
332 | RR->rdlength = ntohs(s); | |
333 | RR->rdata = malloc(RR->rdlength); | |
334 | memcpy(RR->rdata, buf + off, RR->rdlength); | |
335 | break; | |
336 | } | |
298d5ca8 | 337 | off += ntohs(s); |
fb29421b | 338 | assert(off <= sz); |
339 | return off; | |
340 | } | |
341 | ||
7b724b86 | 342 | static unsigned short |
343 | rfc1035Qid(void) | |
344 | { | |
345 | static unsigned short qid = 0x0001; | |
346 | if (++qid == 0xFFFF) | |
347 | qid = 0x0001; | |
348 | return qid; | |
349 | } | |
350 | ||
351 | void | |
352 | rfc1035RRDestroy(rfc1035_rr * rr, int n) | |
353 | { | |
354 | if (rr == NULL) | |
355 | return; | |
356 | assert(n > 0); | |
357 | while (n--) { | |
358 | if (rr[n].rdata) | |
359 | free(rr[n].rdata); | |
360 | } | |
361 | free(rr); | |
362 | } | |
363 | ||
fb29421b | 364 | int |
7b724b86 | 365 | rfc1035AnswersUnpack(const char *buf, |
366 | size_t sz, | |
367 | rfc1035_rr ** records, | |
368 | unsigned short *id) | |
fb29421b | 369 | { |
370 | off_t off = 0; | |
371 | int l; | |
372 | int i; | |
7b724b86 | 373 | int nr = 0; |
374 | rfc1035_header hdr; | |
375 | rfc1035_rr *recs; | |
fb29421b | 376 | memset(&hdr, '\0', sizeof(hdr)); |
377 | off = rfc1035HeaderUnpack(buf + off, sz - off, &hdr); | |
378 | *id = hdr.id; | |
7b724b86 | 379 | rfc1035_errno = 0; |
380 | rfc1035_error_message = NULL; | |
fb29421b | 381 | if (hdr.rcode) { |
382 | rfc1035_errno = (int) hdr.rcode; | |
7b724b86 | 383 | switch (rfc1035_errno) { |
384 | case 0: | |
385 | rfc1035_error_message = "No error condition"; | |
386 | break; | |
387 | case 1: | |
388 | rfc1035_error_message = "Format Error: The name server was " | |
389 | "unable to interpret the query."; | |
390 | break; | |
391 | case 2: | |
392 | rfc1035_error_message = "Server Failure: The name server was " | |
393 | "unable to process this query."; | |
394 | break; | |
395 | case 3: | |
396 | rfc1035_error_message = "Name Error: The domain name does " | |
397 | "not exist."; | |
398 | break; | |
399 | case 4: | |
400 | rfc1035_error_message = "Not Implemented: The name server does " | |
401 | "not support the requested kind of query."; | |
402 | break; | |
403 | case 5: | |
404 | rfc1035_error_message = "Refused: The name server refuses to " | |
405 | "perform the specified operation."; | |
406 | break; | |
407 | default: | |
408 | rfc1035_error_message = "Unknown Error"; | |
409 | break; | |
410 | } | |
fb29421b | 411 | return -rfc1035_errno; |
412 | } | |
413 | i = (int) hdr.qdcount; | |
414 | /* skip question */ | |
415 | while (i--) { | |
416 | do { | |
9bc73deb | 417 | l = (int) (unsigned char) *(buf + off); |
fb29421b | 418 | off++; |
419 | if (l > RFC1035_MAXLABELSZ) { /* compression */ | |
420 | off++; | |
421 | break; | |
422 | } else { | |
423 | off += l; | |
424 | } | |
9bc73deb | 425 | } while (l > 0); /* a zero-length label terminates */ |
fb29421b | 426 | off += 4; /* qtype, qclass */ |
d0017a72 | 427 | assert(off <= sz); |
fb29421b | 428 | } |
429 | i = (int) hdr.ancount; | |
706d89bc | 430 | if (i == 0) |
431 | return 0; | |
7b724b86 | 432 | recs = calloc(i, sizeof(*recs)); |
fb29421b | 433 | while (i--) { |
7b724b86 | 434 | off = rfc1035RRUnpack(buf, sz, off, &recs[i]); |
fb29421b | 435 | assert(off <= sz); |
7b724b86 | 436 | nr++; |
fb29421b | 437 | } |
7b724b86 | 438 | *records = recs; |
439 | return nr; | |
fb29421b | 440 | } |
441 | ||
442 | /* | |
b8cbc836 | 443 | * rfc1035BuildAQuery() |
fb29421b | 444 | * |
445 | * Builds a message buffer with a QUESTION to lookup A records | |
446 | * for a hostname. Caller must allocate 'buf' which should | |
447 | * probably be at least 512 octets. The 'szp' initially | |
448 | * specifies the size of the buffer, on return it contains | |
449 | * the size of the message (i.e. how much to write). | |
450 | * Return value is the query ID. | |
451 | */ | |
452 | unsigned short | |
7b724b86 | 453 | rfc1035BuildAQuery(const char *hostname, char *buf, size_t * szp) |
fb29421b | 454 | { |
7b724b86 | 455 | static rfc1035_header h; |
fb29421b | 456 | off_t offset = 0; |
457 | size_t sz = *szp; | |
458 | memset(&h, '\0', sizeof(h)); | |
7b724b86 | 459 | h.id = rfc1035Qid(); |
fb29421b | 460 | h.qr = 0; |
461 | h.rd = 1; | |
462 | h.opcode = 0; /* QUERY */ | |
463 | h.qdcount = (unsigned int) 1; | |
464 | offset += rfc1035HeaderPack(buf + offset, sz - offset, &h); | |
465 | offset += rfc1035QuestionPack(buf + offset, | |
466 | sz - offset, | |
467 | hostname, | |
468 | RFC1035_TYPE_A, | |
469 | RFC1035_CLASS_IN); | |
470 | assert(offset <= sz); | |
471 | *szp = (size_t) offset; | |
7b724b86 | 472 | return h.id; |
fb29421b | 473 | } |
474 | ||
b8cbc836 | 475 | /* |
476 | * rfc1035BuildPTRQuery() | |
477 | * | |
478 | * Builds a message buffer with a QUESTION to lookup PTR records | |
479 | * for an address. Caller must allocate 'buf' which should | |
480 | * probably be at least 512 octets. The 'szp' initially | |
481 | * specifies the size of the buffer, on return it contains | |
482 | * the size of the message (i.e. how much to write). | |
483 | * Return value is the query ID. | |
484 | */ | |
485 | unsigned short | |
486 | rfc1035BuildPTRQuery(const struct in_addr addr, char *buf, size_t * szp) | |
487 | { | |
488 | static rfc1035_header h; | |
489 | off_t offset = 0; | |
490 | size_t sz = *szp; | |
491 | static char rev[32]; | |
492 | unsigned int i; | |
493 | memset(&h, '\0', sizeof(h)); | |
d0017a72 | 494 | i = (unsigned int) ntohl(addr.s_addr); |
495 | snprintf(rev, 32, "%u.%u.%u.%u.in-addr.arpa.", | |
496 | i & 255, | |
b8cbc836 | 497 | (i >> 8) & 255, |
d0017a72 | 498 | (i >> 16) & 255, |
499 | (i >> 24) & 255); | |
b8cbc836 | 500 | h.id = rfc1035Qid(); |
501 | h.qr = 0; | |
502 | h.rd = 1; | |
503 | h.opcode = 0; /* QUERY */ | |
504 | h.qdcount = (unsigned int) 1; | |
505 | offset += rfc1035HeaderPack(buf + offset, sz - offset, &h); | |
506 | offset += rfc1035QuestionPack(buf + offset, | |
507 | sz - offset, | |
508 | rev, | |
509 | RFC1035_TYPE_PTR, | |
510 | RFC1035_CLASS_IN); | |
511 | assert(offset <= sz); | |
512 | *szp = (size_t) offset; | |
513 | return h.id; | |
514 | } | |
515 | ||
fb29421b | 516 | #if DRIVER |
b8cbc836 | 517 | #include <sys/socket.h> |
518 | #include <sys/time.h> | |
fb29421b | 519 | int |
520 | main(int argc, char *argv[]) | |
521 | { | |
fb29421b | 522 | char input[512]; |
523 | char buf[512]; | |
524 | char rbuf[512]; | |
525 | size_t sz = 512; | |
526 | unsigned short sid; | |
fb29421b | 527 | int s; |
528 | int rl; | |
529 | struct sockaddr_in S; | |
530 | setbuf(stdout, NULL); | |
531 | setbuf(stderr, NULL); | |
532 | s = socket(PF_INET, SOCK_DGRAM, 0); | |
533 | if (s < 0) { | |
534 | perror("socket"); | |
535 | return 1; | |
536 | } | |
537 | while (fgets(input, 512, stdin)) { | |
b8cbc836 | 538 | struct in_addr junk; |
fb29421b | 539 | strtok(input, "\r\n"); |
540 | memset(buf, '\0', 512); | |
b8cbc836 | 541 | sz = 512; |
542 | if (inet_aton(input, &junk)) { | |
543 | sid = rfc1035BuildPTRQuery(junk, buf, &sz); | |
544 | } else { | |
545 | sid = rfc1035BuildAQuery(input, buf, &sz); | |
546 | } | |
fb29421b | 547 | memset(&S, '\0', sizeof(S)); |
548 | S.sin_family = AF_INET; | |
549 | S.sin_port = htons(53); | |
550 | S.sin_addr.s_addr = inet_addr("128.117.28.219"); | |
b8cbc836 | 551 | sendto(s, buf, sz, 0, (struct sockaddr *) &S, sizeof(S)); |
fb29421b | 552 | do { |
7b724b86 | 553 | fd_set R; |
554 | struct timeval to; | |
fb29421b | 555 | FD_ZERO(&R); |
556 | FD_SET(s, &R); | |
557 | to.tv_sec = 10; | |
558 | to.tv_usec = 0; | |
7b724b86 | 559 | rl = select(s + 1, &R, NULL, NULL, &to); |
560 | } while (0); | |
561 | if (rl < 1) { | |
562 | printf("TIMEOUT\n"); | |
563 | continue; | |
564 | } | |
fb29421b | 565 | memset(rbuf, '\0', 512); |
566 | rl = recv(s, rbuf, 512, 0); | |
567 | { | |
568 | unsigned short rid; | |
569 | int i; | |
570 | int n; | |
b8cbc836 | 571 | rfc1035_rr *answers = NULL; |
572 | n = rfc1035AnswersUnpack(rbuf, | |
fb29421b | 573 | rl, |
b8cbc836 | 574 | &answers, |
575 | &rid); | |
fb29421b | 576 | if (rid != sid) { |
577 | printf("ERROR, ID mismatch (%#hx, %#hx)\n", sid, rid); | |
578 | } else if (n < 0) { | |
579 | printf("ERROR %d\n", rfc1035_errno); | |
580 | } else { | |
b8cbc836 | 581 | printf("%d answers\n", n); |
582 | for (i = 0; i < n; i++) { | |
583 | if (answers[i].type == RFC1035_TYPE_A) { | |
584 | struct in_addr a; | |
585 | memcpy(&a, answers[i].rdata, 4); | |
586 | printf("A\t%d\t%s\n", answers[i].ttl, inet_ntoa(a)); | |
587 | } else if (answers[i].type == RFC1035_TYPE_PTR) { | |
588 | char ptr[128]; | |
589 | strncpy(ptr, answers[i].rdata, answers[i].rdlength); | |
590 | printf("PTR\t%d\t%s\n", answers[i].ttl, ptr); | |
591 | } else { | |
592 | fprintf(stderr, "can't print answer type %d\n", | |
593 | (int) answers[i].type); | |
594 | } | |
595 | } | |
fb29421b | 596 | } |
597 | } | |
598 | } | |
599 | return 0; | |
600 | } | |
601 | #endif |