]> git.ipfire.org Git - thirdparty/squid.git/blob - lib/rfc1035.c
fix headers to allow inclusion into C++ source
[thirdparty/squid.git] / lib / rfc1035.c
1
2 /*
3 * $Id: rfc1035.c,v 1.27 2002/09/15 06:40:54 robertc Exp $
4 *
5 * Low level DNS protocol routines
6 * AUTHOR: Duane Wessels
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see 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
36 /*
37 * KNOWN BUGS:
38 *
39 * UDP replies with TC set should be retried via TCP
40 */
41
42 #include "config.h"
43
44 #if HAVE_STDIO_H
45 #include <stdio.h>
46 #endif
47 #if HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
50 #if HAVE_STDLIB_H
51 #include <stdlib.h>
52 #endif
53 #if HAVE_MEMORY_H
54 #include <memory.h>
55 #endif
56 #if HAVE_SYS_TYPES_H
57 #include <sys/types.h>
58 #endif
59 #if HAVE_ASSERT_H
60 #include <assert.h>
61 #endif
62 #if HAVE_NETINET_IN_H
63 #include <netinet/in.h>
64 #endif
65 #if HAVE_ARPA_INET_H
66 #include <arpa/inet.h>
67 #endif
68 #if HAVE_STRINGS_H
69 #include <strings.h>
70 #endif
71
72 #include "rfc1035.h"
73 #include "snprintf.h"
74
75 #define RFC1035_MAXLABELSZ 63
76 #define rfc1035_unpack_error 15
77
78 #if 0
79 #define RFC1035_UNPACK_DEBUG fprintf(stderr, "unpack error at %s:%d\n", __FILE__,__LINE__)
80 #else
81 #define RFC1035_UNPACK_DEBUG (void)0
82 #endif
83
84
85 typedef struct _rfc1035_header rfc1035_header;
86
87 int rfc1035_errno;
88 const char *rfc1035_error_message;
89 struct _rfc1035_header {
90 unsigned short id;
91 unsigned int qr:1;
92 unsigned int opcode:4;
93 unsigned int aa:1;
94 unsigned int tc:1;
95 unsigned int rd:1;
96 unsigned int ra:1;
97 unsigned int rcode:4;
98 unsigned short qdcount;
99 unsigned short ancount;
100 unsigned short nscount;
101 unsigned short arcount;
102 };
103
104 static const char *Alphanum =
105 "abcdefghijklmnopqrstuvwxyz"
106 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
107 "0123456789";
108
109
110 /*
111 * rfc1035HeaderPack()
112 *
113 * Packs a rfc1035_header structure into a buffer.
114 * Returns number of octets packed (should always be 12)
115 */
116 static off_t
117 rfc1035HeaderPack(char *buf, size_t sz, rfc1035_header * hdr)
118 {
119 off_t off = 0;
120 unsigned short s;
121 unsigned short t;
122 assert(sz >= 12);
123 s = htons(hdr->id);
124 memcpy(buf + off, &s, sizeof(s));
125 off += sizeof(s);
126 t = 0;
127 t |= hdr->qr << 15;
128 t |= (hdr->opcode << 11);
129 t |= (hdr->aa << 10);
130 t |= (hdr->tc << 9);
131 t |= (hdr->rd << 8);
132 t |= (hdr->ra << 7);
133 t |= hdr->rcode;
134 s = htons(t);
135 memcpy(buf + off, &s, sizeof(s));
136 off += sizeof(s);
137 s = htons(hdr->qdcount);
138 memcpy(buf + off, &s, sizeof(s));
139 off += sizeof(s);
140 s = htons(hdr->ancount);
141 memcpy(buf + off, &s, sizeof(s));
142 off += sizeof(s);
143 s = htons(hdr->nscount);
144 memcpy(buf + off, &s, sizeof(s));
145 off += sizeof(s);
146 s = htons(hdr->arcount);
147 memcpy(buf + off, &s, sizeof(s));
148 off += sizeof(s);
149 assert(off == 12);
150 return off;
151 }
152
153 /*
154 * rfc1035LabelPack()
155 *
156 * Packs a label into a buffer. The format of
157 * a label is one octet specifying the number of character
158 * bytes to follow. Labels must be smaller than 64 octets.
159 * Returns number of octets packed.
160 */
161 static off_t
162 rfc1035LabelPack(char *buf, size_t sz, const char *label)
163 {
164 off_t off = 0;
165 size_t len = label ? strlen(label) : 0;
166 if (label)
167 assert(!strchr(label, '.'));
168 if (len > RFC1035_MAXLABELSZ)
169 len = RFC1035_MAXLABELSZ;
170 assert(sz >= len + 1);
171 *(buf + off) = (char) len;
172 off++;
173 memcpy(buf + off, label, len);
174 off += len;
175 return off;
176 }
177
178 /*
179 * rfc1035NamePack()
180 *
181 * Packs a name into a buffer. Names are packed as a
182 * sequence of labels, terminated with NULL label.
183 * Note message compression is not supported here.
184 * Returns number of octets packed.
185 */
186 static off_t
187 rfc1035NamePack(char *buf, size_t sz, const char *name)
188 {
189 off_t off = 0;
190 char *copy = strdup(name);
191 char *t;
192 /*
193 * NOTE: use of strtok here makes names like foo....com valid.
194 */
195 for (t = strtok(copy, "."); t; t = strtok(NULL, "."))
196 off += rfc1035LabelPack(buf + off, sz - off, t);
197 free(copy);
198 off += rfc1035LabelPack(buf + off, sz - off, NULL);
199 assert(off <= sz);
200 return off;
201 }
202
203 /*
204 * rfc1035QuestionPack()
205 *
206 * Packs a QUESTION section of a message.
207 * Returns number of octets packed.
208 */
209 static off_t
210 rfc1035QuestionPack(char *buf,
211 size_t sz,
212 const char *name,
213 unsigned short type,
214 unsigned short _class)
215 {
216 off_t off = 0;
217 unsigned short s;
218 off += rfc1035NamePack(buf + off, sz - off, name);
219 s = htons(type);
220 memcpy(buf + off, &s, sizeof(s));
221 off += sizeof(s);
222 s = htons(_class);
223 memcpy(buf + off, &s, sizeof(s));
224 off += sizeof(s);
225 assert(off <= sz);
226 return off;
227 }
228
229 /*
230 * rfc1035HeaderUnpack()
231 *
232 * Unpacks a RFC1035 message header buffer into a rfc1035_header
233 * structure.
234 *
235 * Updates the buffer offset, which is the same as number of
236 * octects unpacked since the header starts at offset 0.
237 *
238 * Returns 0 (success) or 1 (error)
239 */
240 static int
241 rfc1035HeaderUnpack(const char *buf, size_t sz, off_t * off, rfc1035_header * h)
242 {
243 unsigned short s;
244 unsigned short t;
245 assert(*off == 0);
246 /*
247 * The header is 12 octets. This is a bogus message if the size
248 * is less than that.
249 */
250 if (sz < 12)
251 return 1;
252 memcpy(&s, buf + (*off), sizeof(s));
253 (*off) += sizeof(s);
254 h->id = ntohs(s);
255 memcpy(&s, buf + (*off), sizeof(s));
256 (*off) += sizeof(s);
257 t = ntohs(s);
258 h->qr = (t >> 15) & 0x01;
259 h->opcode = (t >> 11) & 0x0F;
260 h->aa = (t >> 10) & 0x01;
261 h->tc = (t >> 9) & 0x01;
262 h->rd = (t >> 8) & 0x01;
263 h->ra = (t >> 7) & 0x01;
264 /*
265 * We might want to check that the reserved 'Z' bits (6-4) are
266 * all zero as per RFC 1035. If not the message should be
267 * rejected.
268 */
269 h->rcode = t & 0x0F;
270 memcpy(&s, buf + (*off), sizeof(s));
271 (*off) += sizeof(s);
272 h->qdcount = ntohs(s);
273 memcpy(&s, buf + (*off), sizeof(s));
274 (*off) += sizeof(s);
275 h->ancount = ntohs(s);
276 memcpy(&s, buf + (*off), sizeof(s));
277 (*off) += sizeof(s);
278 h->nscount = ntohs(s);
279 memcpy(&s, buf + (*off), sizeof(s));
280 (*off) += sizeof(s);
281 h->arcount = ntohs(s);
282 assert((*off) == 12);
283 return 0;
284 }
285
286 /*
287 * rfc1035NameUnpack()
288 *
289 * Unpacks a Name in a message buffer into a char*.
290 * Note 'buf' points to the beginning of the whole message,
291 * 'off' points to the spot where the Name begins, and 'sz'
292 * is the size of the whole message. 'name' must be allocated
293 * by the caller.
294 *
295 * Supports the RFC1035 message compression through recursion.
296 *
297 * Updates the new buffer offset.
298 *
299 * Returns 0 (success) or 1 (error)
300 */
301 static int
302 rfc1035NameUnpack(const char *buf, size_t sz, off_t * off, char *name, size_t ns, int rdepth)
303 {
304 off_t no = 0;
305 unsigned char c;
306 size_t len;
307 assert(ns > 0);
308 do {
309 assert((*off) < sz);
310 c = *(buf + (*off));
311 if (c > 191) {
312 /* blasted compression */
313 unsigned short s;
314 off_t ptr;
315 if (rdepth > 64) /* infinite pointer loop */
316 return 1;
317 memcpy(&s, buf + (*off), sizeof(s));
318 s = ntohs(s);
319 (*off) += sizeof(s);
320 /* Sanity check */
321 if ((*off) >= sz)
322 return 1;
323 ptr = s & 0x3FFF;
324 /* Make sure the pointer is inside this message */
325 if (ptr >= sz)
326 return 1;
327 return rfc1035NameUnpack(buf, sz, &ptr, name + no, ns - no, rdepth + 1);
328 } else if (c > RFC1035_MAXLABELSZ) {
329 /*
330 * "(The 10 and 01 combinations are reserved for future use.)"
331 */
332 return 1;
333 } else {
334 (*off)++;
335 len = (size_t) c;
336 if (len == 0)
337 break;
338 if (len > (ns - no - 1)) /* label won't fit */
339 return 1;
340 if ((*off) + len > sz) /* message is too short */
341 return 1;
342 memcpy(name + no, buf + (*off), len);
343 (*off) += len;
344 no += len;
345 *(name + (no++)) = '.';
346 }
347 } while (c > 0 && no < ns);
348 *(name + no - 1) = '\0';
349 /* make sure we didn't allow someone to overflow the name buffer */
350 assert(no <= ns);
351 return 0;
352 }
353
354 /*
355 * rfc1035RRUnpack()
356 *
357 * Unpacks a RFC1035 Resource Record into 'RR' from a message buffer.
358 * The caller must free RR->rdata!
359 *
360 * Updates the new message buffer offset.
361 *
362 * Returns 0 (success) or 1 (error)
363 */
364 static int
365 rfc1035RRUnpack(const char *buf, size_t sz, off_t * off, rfc1035_rr * RR)
366 {
367 unsigned short s;
368 unsigned int i;
369 off_t rdata_off;
370 if (rfc1035NameUnpack(buf, sz, off, RR->name, RFC1035_MAXHOSTNAMESZ, 0)) {
371 RFC1035_UNPACK_DEBUG;
372 memset(RR, '\0', sizeof(*RR));
373 return 1;
374 }
375 /*
376 * Make sure the remaining message has enough octets for the
377 * rest of the RR fields.
378 */
379 if ((*off) + 10 > sz) {
380 RFC1035_UNPACK_DEBUG;
381 memset(RR, '\0', sizeof(*RR));
382 return 1;
383 }
384 memcpy(&s, buf + (*off), sizeof(s));
385 (*off) += sizeof(s);
386 RR->type = ntohs(s);
387 memcpy(&s, buf + (*off), sizeof(s));
388 (*off) += sizeof(s);
389 RR->_class = ntohs(s);
390 memcpy(&i, buf + (*off), sizeof(i));
391 (*off) += sizeof(i);
392 RR->ttl = ntohl(i);
393 memcpy(&s, buf + (*off), sizeof(s));
394 (*off) += sizeof(s);
395 if ((*off) + ntohs(s) > sz) {
396 /*
397 * We got a truncated packet. 'dnscache' truncates UDP
398 * replies at 512 octets, as per RFC 1035.
399 */
400 RFC1035_UNPACK_DEBUG;
401 memset(RR, '\0', sizeof(*RR));
402 return 1;
403 }
404 RR->rdlength = ntohs(s);
405 switch (RR->type) {
406 case RFC1035_TYPE_PTR:
407 RR->rdata = malloc(RFC1035_MAXHOSTNAMESZ);
408 rdata_off = *off;
409 if (rfc1035NameUnpack(buf, sz, &rdata_off, RR->rdata, RFC1035_MAXHOSTNAMESZ, 0))
410 return 1;
411 if (rdata_off != ((*off) + RR->rdlength)) {
412 /*
413 * This probably doesn't happen for valid packets, but
414 * I want to make sure that NameUnpack doesn't go beyond
415 * the RDATA area.
416 */
417 RFC1035_UNPACK_DEBUG;
418 memset(RR, '\0', sizeof(*RR));
419 return 1;
420 }
421 break;
422 case RFC1035_TYPE_A:
423 default:
424 RR->rdata = malloc(RR->rdlength);
425 memcpy(RR->rdata, buf + (*off), RR->rdlength);
426 break;
427 }
428 (*off) += RR->rdlength;
429 assert((*off) <= sz);
430 return 0;
431 }
432
433 static unsigned short
434 rfc1035Qid(void)
435 {
436 static unsigned short qid = 0x0001;
437 if (++qid == 0xFFFF)
438 qid = 0x0001;
439 return qid;
440 }
441
442 static void
443 rfc1035SetErrno(int n)
444 {
445 switch (rfc1035_errno = n) {
446 case 0:
447 rfc1035_error_message = "No error condition";
448 break;
449 case 1:
450 rfc1035_error_message = "Format Error: The name server was "
451 "unable to interpret the query.";
452 break;
453 case 2:
454 rfc1035_error_message = "Server Failure: The name server was "
455 "unable to process this query.";
456 break;
457 case 3:
458 rfc1035_error_message = "Name Error: The domain name does "
459 "not exist.";
460 break;
461 case 4:
462 rfc1035_error_message = "Not Implemented: The name server does "
463 "not support the requested kind of query.";
464 break;
465 case 5:
466 rfc1035_error_message = "Refused: The name server refuses to "
467 "perform the specified operation.";
468 break;
469 case rfc1035_unpack_error:
470 rfc1035_error_message = "The DNS reply message is corrupt or could "
471 "not be safely parsed.";
472 break;
473 default:
474 rfc1035_error_message = "Unknown Error";
475 break;
476 }
477 }
478
479 void
480 rfc1035RRDestroy(rfc1035_rr * rr, int n)
481 {
482 if (rr == NULL)
483 return;
484 assert(n > 0);
485 while (n--) {
486 if (rr[n].rdata)
487 free(rr[n].rdata);
488 }
489 free(rr);
490 }
491
492 /*
493 * rfc1035AnswersUnpack()
494 *
495 * Takes the contents of a DNS reply and fills in an array
496 * of resource record structures. The records array is allocated
497 * here, and should be freed by calling rfc1035RRDestroy().
498 *
499 * Returns number of records unpacked, zero if DNS reply indicates
500 * zero answers, or an error number < 0.
501 */
502
503 int
504 rfc1035AnswersUnpack(const char *buf,
505 size_t sz,
506 rfc1035_rr ** records,
507 unsigned short *id)
508 {
509 off_t off = 0;
510 int l;
511 int i;
512 int nr = 0;
513 rfc1035_header hdr;
514 rfc1035_rr *recs;
515 memset(&hdr, '\0', sizeof(hdr));
516 if (rfc1035HeaderUnpack(buf + off, sz - off, &off, &hdr)) {
517 RFC1035_UNPACK_DEBUG;
518 rfc1035SetErrno(rfc1035_unpack_error);
519 return -rfc1035_unpack_error;
520 }
521 *id = hdr.id;
522 rfc1035_errno = 0;
523 rfc1035_error_message = NULL;
524 if (hdr.rcode) {
525 RFC1035_UNPACK_DEBUG;
526 rfc1035SetErrno((int) hdr.rcode);
527 return -rfc1035_errno;
528 }
529 i = (int) hdr.qdcount;
530 /* skip question */
531 while (i--) {
532 do {
533 l = (int) (unsigned char) *(buf + off);
534 off++;
535 if (l > 191) { /* compression */
536 off++;
537 break;
538 } else if (l > RFC1035_MAXLABELSZ) {
539 /* illegal combination of compression bits */
540 RFC1035_UNPACK_DEBUG;
541 rfc1035SetErrno(rfc1035_unpack_error);
542 return -rfc1035_unpack_error;
543 } else {
544 off += l;
545 }
546 } while (l > 0); /* a zero-length label terminates */
547 off += 4; /* qtype, qclass */
548 if (off > sz) {
549 RFC1035_UNPACK_DEBUG;
550 rfc1035SetErrno(rfc1035_unpack_error);
551 return -rfc1035_unpack_error;
552 }
553 }
554 i = (int) hdr.ancount;
555 if (i == 0)
556 return 0;
557 recs = calloc(i, sizeof(*recs));
558 while (i--) {
559 if (off >= sz) { /* corrupt packet */
560 RFC1035_UNPACK_DEBUG;
561 break;
562 }
563 if (rfc1035RRUnpack(buf, sz, &off, &recs[i])) { /* corrupt RR */
564 RFC1035_UNPACK_DEBUG;
565 break;
566 }
567 nr++;
568 }
569 if (nr == 0) {
570 /*
571 * we expected to unpack some answers (ancount != 0), but
572 * didn't actually get any.
573 */
574 free(recs);
575 rfc1035SetErrno(rfc1035_unpack_error);
576 return -rfc1035_unpack_error;
577 }
578 *records = recs;
579 return nr;
580 }
581
582 /*
583 * rfc1035BuildAQuery()
584 *
585 * Builds a message buffer with a QUESTION to lookup A records
586 * for a hostname. Caller must allocate 'buf' which should
587 * probably be at least 512 octets. The 'szp' initially
588 * specifies the size of the buffer, on return it contains
589 * the size of the message (i.e. how much to write).
590 * Return value is the query ID.
591 */
592 unsigned short
593 rfc1035BuildAQuery(const char *hostname, char *buf, size_t * szp)
594 {
595 static rfc1035_header h;
596 size_t offset = 0;
597 size_t sz = *szp;
598 memset(&h, '\0', sizeof(h));
599 /* the first char of hostname must be alphanmeric */
600 if (NULL == strchr(Alphanum, *hostname)) {
601 rfc1035SetErrno(3);
602 return 0;
603 }
604 h.id = rfc1035Qid();
605 h.qr = 0;
606 h.rd = 1;
607 h.opcode = 0; /* QUERY */
608 h.qdcount = (unsigned int) 1;
609 offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
610 offset += rfc1035QuestionPack(buf + offset,
611 sz - offset,
612 hostname,
613 RFC1035_TYPE_A,
614 RFC1035_CLASS_IN);
615 assert(offset <= sz);
616 *szp = (size_t) offset;
617 return h.id;
618 }
619
620 /*
621 * rfc1035BuildPTRQuery()
622 *
623 * Builds a message buffer with a QUESTION to lookup PTR records
624 * for an address. Caller must allocate 'buf' which should
625 * probably be at least 512 octets. The 'szp' initially
626 * specifies the size of the buffer, on return it contains
627 * the size of the message (i.e. how much to write).
628 * Return value is the query ID.
629 */
630 unsigned short
631 rfc1035BuildPTRQuery(const struct in_addr addr, char *buf, size_t * szp)
632 {
633 static rfc1035_header h;
634 size_t offset = 0;
635 size_t sz = *szp;
636 static char rev[32];
637 unsigned int i;
638 memset(&h, '\0', sizeof(h));
639 i = (unsigned int) ntohl(addr.s_addr);
640 snprintf(rev, 32, "%u.%u.%u.%u.in-addr.arpa.",
641 i & 255,
642 (i >> 8) & 255,
643 (i >> 16) & 255,
644 (i >> 24) & 255);
645 h.id = rfc1035Qid();
646 h.qr = 0;
647 h.rd = 1;
648 h.opcode = 0; /* QUERY */
649 h.qdcount = (unsigned int) 1;
650 offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
651 offset += rfc1035QuestionPack(buf + offset,
652 sz - offset,
653 rev,
654 RFC1035_TYPE_PTR,
655 RFC1035_CLASS_IN);
656 assert(offset <= sz);
657 *szp = offset;
658 return h.id;
659 }
660
661 /*
662 * We're going to retry a former query, but we
663 * just need a new ID for it. Lucky for us ID
664 * is the first field in the message buffer.
665 */
666 unsigned short
667 rfc1035RetryQuery(char *buf)
668 {
669 unsigned short qid = rfc1035Qid();
670 unsigned short s = htons(qid);
671 memcpy(buf, &s, sizeof(s));
672 return qid;
673 }
674
675 #if DRIVER
676 #include <sys/socket.h>
677 #include <sys/time.h>
678 int
679 main(int argc, char *argv[])
680 {
681 char input[512];
682 char buf[512];
683 char rbuf[512];
684 size_t sz = 512;
685 unsigned short sid;
686 int s;
687 int rl;
688 struct sockaddr_in S;
689 if (3 != argc) {
690 fprintf(stderr, "usage: %s ip port\n", argv[0]);
691 return 1;
692 }
693 setbuf(stdout, NULL);
694 setbuf(stderr, NULL);
695 s = socket(PF_INET, SOCK_DGRAM, 0);
696 if (s < 0) {
697 perror("socket");
698 return 1;
699 }
700 memset(&S, '\0', sizeof(S));
701 S.sin_family = AF_INET;
702 S.sin_port = htons(atoi(argv[2]));
703 S.sin_addr.s_addr = inet_addr(argv[1]);
704 while (fgets(input, 512, stdin)) {
705 struct in_addr junk;
706 strtok(input, "\r\n");
707 memset(buf, '\0', 512);
708 sz = 512;
709 if (inet_aton(input, &junk)) {
710 sid = rfc1035BuildPTRQuery(junk, buf, &sz);
711 } else {
712 sid = rfc1035BuildAQuery(input, buf, &sz);
713 }
714 sendto(s, buf, sz, 0, (struct sockaddr *) &S, sizeof(S));
715 do {
716 fd_set R;
717 struct timeval to;
718 FD_ZERO(&R);
719 FD_SET(s, &R);
720 to.tv_sec = 10;
721 to.tv_usec = 0;
722 rl = select(s + 1, &R, NULL, NULL, &to);
723 } while (0);
724 if (rl < 1) {
725 printf("TIMEOUT\n");
726 continue;
727 }
728 memset(rbuf, '\0', 512);
729 rl = recv(s, rbuf, 512, 0);
730 {
731 unsigned short rid = 0;
732 int i;
733 int n;
734 rfc1035_rr *answers = NULL;
735 n = rfc1035AnswersUnpack(rbuf,
736 rl,
737 &answers,
738 &rid);
739 if (n < 0) {
740 printf("ERROR %d\n", rfc1035_errno);
741 } else if (rid != sid) {
742 printf("ERROR, ID mismatch (%#hx, %#hx)\n", sid, rid);
743 } else {
744 printf("%d answers\n", n);
745 for (i = 0; i < n; i++) {
746 if (answers[i].type == RFC1035_TYPE_A) {
747 struct in_addr a;
748 memcpy(&a, answers[i].rdata, 4);
749 printf("A\t%d\t%s\n", answers[i].ttl, inet_ntoa(a));
750 } else if (answers[i].type == RFC1035_TYPE_PTR) {
751 char ptr[128];
752 strncpy(ptr, answers[i].rdata, answers[i].rdlength);
753 printf("PTR\t%d\t%s\n", answers[i].ttl, ptr);
754 } else {
755 fprintf(stderr, "can't print answer type %d\n",
756 (int) answers[i].type);
757 }
758 }
759 }
760 }
761 }
762 return 0;
763 }
764 #endif