]> git.ipfire.org Git - thirdparty/squid.git/blame - lib/rfc1035.c
Bug #1197: DNS related memory leak on certain malformed DNS responses
[thirdparty/squid.git] / lib / rfc1035.c
CommitLineData
461eef68 1
7f3647d6 2/*
d443933d 3 * $Id: rfc1035.c,v 1.34 2005/01/23 14:55:45 serassio Exp $
7f3647d6 4 *
5 * Low level DNS protocol routines
6 * AUTHOR: Duane Wessels
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
7f3647d6 9 * ----------------------------------------------------------
10 *
2b6662ba 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.
7f3647d6 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.
2b6662ba 24 *
7f3647d6 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.
2b6662ba 29 *
7f3647d6 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
c415c128 36/*
37 * KNOWN BUGS:
38 *
39 * UDP replies with TC set should be retried via TCP
40 */
41
fb29421b 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
7b724b86 72#include "rfc1035.h"
d86af726 73#include "snprintf.h"
fb29421b 74
75#define RFC1035_MAXLABELSZ 63
0768dfce 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
fb29421b 84
7b724b86 85typedef struct _rfc1035_header rfc1035_header;
fb29421b 86
87int rfc1035_errno;
7b724b86 88const char *rfc1035_error_message;
89struct _rfc1035_header {
fb29421b 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
76cb2b26 104static const char *Alphanum =
105"abcdefghijklmnopqrstuvwxyz"
106"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
107"0123456789";
108
0768dfce 109
fb29421b 110/*
111 * rfc1035HeaderPack()
112 *
7b724b86 113 * Packs a rfc1035_header structure into a buffer.
fb29421b 114 * Returns number of octets packed (should always be 12)
115 */
116static off_t
7b724b86 117rfc1035HeaderPack(char *buf, size_t sz, rfc1035_header * hdr)
fb29421b 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 */
161static off_t
162rfc1035LabelPack(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 */
2d72d4fd 186static off_t
fb29421b 187rfc1035NamePack(char *buf, size_t sz, const char *name)
188{
189 off_t off = 0;
190 char *copy = strdup(name);
191 char *t;
0a8e6ec2 192 /*
193 * NOTE: use of strtok here makes names like foo....com valid.
194 */
fb29421b 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 */
209static off_t
210rfc1035QuestionPack(char *buf,
211 size_t sz,
212 const char *name,
213 unsigned short type,
29b8d8d6 214 unsigned short _class)
fb29421b 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);
29b8d8d6 222 s = htons(_class);
fb29421b 223 memcpy(buf + off, &s, sizeof(s));
224 off += sizeof(s);
225 assert(off <= sz);
226 return off;
227}
228
229/*
230 * rfc1035HeaderUnpack()
231 *
7b724b86 232 * Unpacks a RFC1035 message header buffer into a rfc1035_header
fb29421b 233 * structure.
0768dfce 234 *
235 * Updates the buffer offset, which is the same as number of
fb29421b 236 * octects unpacked since the header starts at offset 0.
0768dfce 237 *
238 * Returns 0 (success) or 1 (error)
fb29421b 239 */
0768dfce 240static int
241rfc1035HeaderUnpack(const char *buf, size_t sz, off_t * off, rfc1035_header * h)
fb29421b 242{
243 unsigned short s;
244 unsigned short t;
0768dfce 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);
fb29421b 254 h->id = ntohs(s);
0768dfce 255 memcpy(&s, buf + (*off), sizeof(s));
256 (*off) += sizeof(s);
fb29421b 257 t = ntohs(s);
258 h->qr = (t >> 15) & 0x01;
259 h->opcode = (t >> 11) & 0x0F;
260 h->aa = (t >> 10) & 0x01;
c415c128 261 h->tc = (t >> 9) & 0x01;
fb29421b 262 h->rd = (t >> 8) & 0x01;
263 h->ra = (t >> 7) & 0x01;
0768dfce 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 */
fb29421b 269 h->rcode = t & 0x0F;
0768dfce 270 memcpy(&s, buf + (*off), sizeof(s));
271 (*off) += sizeof(s);
fb29421b 272 h->qdcount = ntohs(s);
0768dfce 273 memcpy(&s, buf + (*off), sizeof(s));
274 (*off) += sizeof(s);
fb29421b 275 h->ancount = ntohs(s);
0768dfce 276 memcpy(&s, buf + (*off), sizeof(s));
277 (*off) += sizeof(s);
fb29421b 278 h->nscount = ntohs(s);
0768dfce 279 memcpy(&s, buf + (*off), sizeof(s));
280 (*off) += sizeof(s);
fb29421b 281 h->arcount = ntohs(s);
0768dfce 282 assert((*off) == 12);
283 return 0;
fb29421b 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 *
0768dfce 297 * Updates the new buffer offset.
298 *
299 * Returns 0 (success) or 1 (error)
fb29421b 300 */
0768dfce 301static int
0eaa7165 302rfc1035NameUnpack(const char *buf, size_t sz, off_t * off, char *name, size_t ns, int rdepth)
fb29421b 303{
304 off_t no = 0;
305 unsigned char c;
306 size_t len;
307 assert(ns > 0);
308 do {
0768dfce 309 assert((*off) < sz);
310 c = *(buf + (*off));
311 if (c > 191) {
c4eb7525 312 /* blasted compression */
fb29421b 313 unsigned short s;
314 off_t ptr;
db17c597 315 if (rdepth > 64) /* infinite pointer loop */
13c900c4 316 return 1;
0768dfce 317 memcpy(&s, buf + (*off), sizeof(s));
fb29421b 318 s = ntohs(s);
0768dfce 319 (*off) += sizeof(s);
320 /* Sanity check */
321 if ((*off) >= sz)
322 return 1;
fb29421b 323 ptr = s & 0x3FFF;
0768dfce 324 /* Make sure the pointer is inside this message */
325 if (ptr >= sz)
326 return 1;
0eaa7165 327 return rfc1035NameUnpack(buf, sz, &ptr, name + no, ns - no, rdepth + 1);
26527d3b 328 } else if (c > RFC1035_MAXLABELSZ) {
0768dfce 329 /*
330 * "(The 10 and 01 combinations are reserved for future use.)"
331 */
332 return 1;
fb29421b 333 } else {
0768dfce 334 (*off)++;
fb29421b 335 len = (size_t) c;
336 if (len == 0)
337 break;
13c900c4 338 if (len > (ns - no - 1)) /* label won't fit */
339 return 1;
1a8a1b50 340 if ((*off) + len >= sz) /* message is too short */
0768dfce 341 return 1;
342 memcpy(name + no, buf + (*off), len);
343 (*off) += len;
fb29421b 344 no += len;
345 *(name + (no++)) = '.';
346 }
13c900c4 347 } while (c > 0 && no < ns);
4775d711 348 if (no)
349 *(name + no - 1) = '\0';
350 else
351 *name = '\0';
0768dfce 352 /* make sure we didn't allow someone to overflow the name buffer */
fb29421b 353 assert(no <= ns);
0768dfce 354 return 0;
fb29421b 355}
356
357/*
358 * rfc1035RRUnpack()
359 *
360 * Unpacks a RFC1035 Resource Record into 'RR' from a message buffer.
361 * The caller must free RR->rdata!
0768dfce 362 *
363 * Updates the new message buffer offset.
364 *
365 * Returns 0 (success) or 1 (error)
fb29421b 366 */
0768dfce 367static int
368rfc1035RRUnpack(const char *buf, size_t sz, off_t * off, rfc1035_rr * RR)
fb29421b 369{
370 unsigned short s;
371 unsigned int i;
26527d3b 372 off_t rdata_off;
13c900c4 373 if (rfc1035NameUnpack(buf, sz, off, RR->name, RFC1035_MAXHOSTNAMESZ, 0)) {
0768dfce 374 RFC1035_UNPACK_DEBUG;
375 memset(RR, '\0', sizeof(*RR));
376 return 1;
377 }
378 /*
379 * Make sure the remaining message has enough octets for the
380 * rest of the RR fields.
381 */
382 if ((*off) + 10 > sz) {
383 RFC1035_UNPACK_DEBUG;
384 memset(RR, '\0', sizeof(*RR));
385 return 1;
386 }
387 memcpy(&s, buf + (*off), sizeof(s));
388 (*off) += sizeof(s);
fb29421b 389 RR->type = ntohs(s);
0768dfce 390 memcpy(&s, buf + (*off), sizeof(s));
391 (*off) += sizeof(s);
29b8d8d6 392 RR->_class = ntohs(s);
0768dfce 393 memcpy(&i, buf + (*off), sizeof(i));
394 (*off) += sizeof(i);
fb29421b 395 RR->ttl = ntohl(i);
0768dfce 396 memcpy(&s, buf + (*off), sizeof(s));
397 (*off) += sizeof(s);
398 if ((*off) + ntohs(s) > sz) {
c415c128 399 /*
400 * We got a truncated packet. 'dnscache' truncates UDP
0768dfce 401 * replies at 512 octets, as per RFC 1035.
c415c128 402 */
0768dfce 403 RFC1035_UNPACK_DEBUG;
a60011f4 404 memset(RR, '\0', sizeof(*RR));
0768dfce 405 return 1;
c415c128 406 }
26527d3b 407 RR->rdlength = ntohs(s);
b8cbc836 408 switch (RR->type) {
409 case RFC1035_TYPE_PTR:
410 RR->rdata = malloc(RFC1035_MAXHOSTNAMESZ);
26527d3b 411 rdata_off = *off;
13c900c4 412 if (rfc1035NameUnpack(buf, sz, &rdata_off, RR->rdata, RFC1035_MAXHOSTNAMESZ, 0))
0768dfce 413 return 1;
26527d3b 414 if (rdata_off != ((*off) + RR->rdlength)) {
415 /*
416 * This probably doesn't happen for valid packets, but
417 * I want to make sure that NameUnpack doesn't go beyond
418 * the RDATA area.
419 */
420 RFC1035_UNPACK_DEBUG;
421 memset(RR, '\0', sizeof(*RR));
422 return 1;
423 }
b8cbc836 424 break;
425 case RFC1035_TYPE_A:
426 default:
b8cbc836 427 RR->rdata = malloc(RR->rdlength);
0768dfce 428 memcpy(RR->rdata, buf + (*off), RR->rdlength);
b8cbc836 429 break;
430 }
26527d3b 431 (*off) += RR->rdlength;
0768dfce 432 assert((*off) <= sz);
433 return 0;
fb29421b 434}
435
7b724b86 436static unsigned short
437rfc1035Qid(void)
438{
439 static unsigned short qid = 0x0001;
440 if (++qid == 0xFFFF)
441 qid = 0x0001;
442 return qid;
443}
444
76cb2b26 445static void
446rfc1035SetErrno(int n)
447{
448 switch (rfc1035_errno = n) {
449 case 0:
450 rfc1035_error_message = "No error condition";
451 break;
452 case 1:
453 rfc1035_error_message = "Format Error: The name server was "
454 "unable to interpret the query.";
455 break;
456 case 2:
457 rfc1035_error_message = "Server Failure: The name server was "
458 "unable to process this query.";
459 break;
460 case 3:
461 rfc1035_error_message = "Name Error: The domain name does "
462 "not exist.";
463 break;
464 case 4:
465 rfc1035_error_message = "Not Implemented: The name server does "
466 "not support the requested kind of query.";
467 break;
468 case 5:
469 rfc1035_error_message = "Refused: The name server refuses to "
470 "perform the specified operation.";
471 break;
0768dfce 472 case rfc1035_unpack_error:
473 rfc1035_error_message = "The DNS reply message is corrupt or could "
474 "not be safely parsed.";
475 break;
76cb2b26 476 default:
477 rfc1035_error_message = "Unknown Error";
478 break;
479 }
480}
481
7b724b86 482void
483rfc1035RRDestroy(rfc1035_rr * rr, int n)
484{
485 if (rr == NULL)
486 return;
487 assert(n > 0);
488 while (n--) {
489 if (rr[n].rdata)
490 free(rr[n].rdata);
491 }
492 free(rr);
493}
494
0768dfce 495/*
496 * rfc1035AnswersUnpack()
497 *
498 * Takes the contents of a DNS reply and fills in an array
499 * of resource record structures. The records array is allocated
500 * here, and should be freed by calling rfc1035RRDestroy().
501 *
502 * Returns number of records unpacked, zero if DNS reply indicates
503 * zero answers, or an error number < 0.
504 */
505
fb29421b 506int
7b724b86 507rfc1035AnswersUnpack(const char *buf,
508 size_t sz,
509 rfc1035_rr ** records,
510 unsigned short *id)
fb29421b 511{
0768dfce 512 off_t off = 0;
fb29421b 513 int l;
514 int i;
7b724b86 515 int nr = 0;
516 rfc1035_header hdr;
517 rfc1035_rr *recs;
fb29421b 518 memset(&hdr, '\0', sizeof(hdr));
0768dfce 519 if (rfc1035HeaderUnpack(buf + off, sz - off, &off, &hdr)) {
520 RFC1035_UNPACK_DEBUG;
521 rfc1035SetErrno(rfc1035_unpack_error);
522 return -rfc1035_unpack_error;
523 }
fb29421b 524 *id = hdr.id;
7b724b86 525 rfc1035_errno = 0;
526 rfc1035_error_message = NULL;
fb29421b 527 if (hdr.rcode) {
0768dfce 528 RFC1035_UNPACK_DEBUG;
76cb2b26 529 rfc1035SetErrno((int) hdr.rcode);
fb29421b 530 return -rfc1035_errno;
531 }
532 i = (int) hdr.qdcount;
533 /* skip question */
534 while (i--) {
535 do {
9bc73deb 536 l = (int) (unsigned char) *(buf + off);
fb29421b 537 off++;
26527d3b 538 if (l > 191) { /* compression */
fb29421b 539 off++;
540 break;
26527d3b 541 } else if (l > RFC1035_MAXLABELSZ) {
542 /* illegal combination of compression bits */
543 RFC1035_UNPACK_DEBUG;
544 rfc1035SetErrno(rfc1035_unpack_error);
545 return -rfc1035_unpack_error;
fb29421b 546 } else {
547 off += l;
548 }
9bc73deb 549 } while (l > 0); /* a zero-length label terminates */
fb29421b 550 off += 4; /* qtype, qclass */
0768dfce 551 if (off > sz) {
552 RFC1035_UNPACK_DEBUG;
553 rfc1035SetErrno(rfc1035_unpack_error);
554 return -rfc1035_unpack_error;
555 }
fb29421b 556 }
d443933d 557 if (hdr.ancount == 0)
706d89bc 558 return 0;
d443933d 559 recs = calloc((int)hdr.ancount, sizeof(*recs));
560 for (i = 0; i < (int)hdr.ancount; i++) {
0768dfce 561 if (off >= sz) { /* corrupt packet */
562 RFC1035_UNPACK_DEBUG;
563 break;
564 }
565 if (rfc1035RRUnpack(buf, sz, &off, &recs[i])) { /* corrupt RR */
566 RFC1035_UNPACK_DEBUG;
c415c128 567 break;
0768dfce 568 }
7b724b86 569 nr++;
fb29421b 570 }
0768dfce 571 if (nr == 0) {
572 /*
573 * we expected to unpack some answers (ancount != 0), but
574 * didn't actually get any.
575 */
d9589922 576 free(recs);
0768dfce 577 rfc1035SetErrno(rfc1035_unpack_error);
578 return -rfc1035_unpack_error;
579 }
580 *records = recs;
7b724b86 581 return nr;
fb29421b 582}
583
584/*
b8cbc836 585 * rfc1035BuildAQuery()
fb29421b 586 *
587 * Builds a message buffer with a QUESTION to lookup A records
588 * for a hostname. Caller must allocate 'buf' which should
589 * probably be at least 512 octets. The 'szp' initially
590 * specifies the size of the buffer, on return it contains
591 * the size of the message (i.e. how much to write).
592 * Return value is the query ID.
593 */
594unsigned short
7b724b86 595rfc1035BuildAQuery(const char *hostname, char *buf, size_t * szp)
fb29421b 596{
7b724b86 597 static rfc1035_header h;
2d72d4fd 598 size_t offset = 0;
fb29421b 599 size_t sz = *szp;
600 memset(&h, '\0', sizeof(h));
76cb2b26 601 /* the first char of hostname must be alphanmeric */
cc8df835 602 if (NULL == strchr(Alphanum, *hostname)) {
76cb2b26 603 rfc1035SetErrno(3);
604 return 0;
605 }
7b724b86 606 h.id = rfc1035Qid();
fb29421b 607 h.qr = 0;
608 h.rd = 1;
609 h.opcode = 0; /* QUERY */
610 h.qdcount = (unsigned int) 1;
611 offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
612 offset += rfc1035QuestionPack(buf + offset,
613 sz - offset,
614 hostname,
615 RFC1035_TYPE_A,
616 RFC1035_CLASS_IN);
617 assert(offset <= sz);
618 *szp = (size_t) offset;
7b724b86 619 return h.id;
fb29421b 620}
621
b8cbc836 622/*
623 * rfc1035BuildPTRQuery()
624 *
625 * Builds a message buffer with a QUESTION to lookup PTR records
626 * for an address. Caller must allocate 'buf' which should
627 * probably be at least 512 octets. The 'szp' initially
628 * specifies the size of the buffer, on return it contains
629 * the size of the message (i.e. how much to write).
630 * Return value is the query ID.
631 */
632unsigned short
633rfc1035BuildPTRQuery(const struct in_addr addr, char *buf, size_t * szp)
634{
635 static rfc1035_header h;
2d72d4fd 636 size_t offset = 0;
b8cbc836 637 size_t sz = *szp;
638 static char rev[32];
639 unsigned int i;
640 memset(&h, '\0', sizeof(h));
d0017a72 641 i = (unsigned int) ntohl(addr.s_addr);
642 snprintf(rev, 32, "%u.%u.%u.%u.in-addr.arpa.",
643 i & 255,
b8cbc836 644 (i >> 8) & 255,
d0017a72 645 (i >> 16) & 255,
646 (i >> 24) & 255);
b8cbc836 647 h.id = rfc1035Qid();
648 h.qr = 0;
649 h.rd = 1;
650 h.opcode = 0; /* QUERY */
651 h.qdcount = (unsigned int) 1;
652 offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
653 offset += rfc1035QuestionPack(buf + offset,
654 sz - offset,
655 rev,
656 RFC1035_TYPE_PTR,
657 RFC1035_CLASS_IN);
658 assert(offset <= sz);
2d72d4fd 659 *szp = offset;
b8cbc836 660 return h.id;
661}
662
558be27a 663/*
664 * We're going to retry a former query, but we
665 * just need a new ID for it. Lucky for us ID
666 * is the first field in the message buffer.
667 */
668unsigned short
669rfc1035RetryQuery(char *buf)
670{
671 unsigned short qid = rfc1035Qid();
672 unsigned short s = htons(qid);
673 memcpy(buf, &s, sizeof(s));
674 return qid;
675}
676
fb29421b 677#if DRIVER
b8cbc836 678#include <sys/socket.h>
679#include <sys/time.h>
fb29421b 680int
681main(int argc, char *argv[])
682{
fb29421b 683 char input[512];
684 char buf[512];
685 char rbuf[512];
686 size_t sz = 512;
687 unsigned short sid;
fb29421b 688 int s;
689 int rl;
690 struct sockaddr_in S;
0768dfce 691 if (3 != argc) {
692 fprintf(stderr, "usage: %s ip port\n", argv[0]);
693 return 1;
694 }
fb29421b 695 setbuf(stdout, NULL);
696 setbuf(stderr, NULL);
697 s = socket(PF_INET, SOCK_DGRAM, 0);
698 if (s < 0) {
699 perror("socket");
700 return 1;
701 }
0768dfce 702 memset(&S, '\0', sizeof(S));
703 S.sin_family = AF_INET;
704 S.sin_port = htons(atoi(argv[2]));
705 S.sin_addr.s_addr = inet_addr(argv[1]);
fb29421b 706 while (fgets(input, 512, stdin)) {
b8cbc836 707 struct in_addr junk;
fb29421b 708 strtok(input, "\r\n");
709 memset(buf, '\0', 512);
b8cbc836 710 sz = 512;
711 if (inet_aton(input, &junk)) {
712 sid = rfc1035BuildPTRQuery(junk, buf, &sz);
713 } else {
714 sid = rfc1035BuildAQuery(input, buf, &sz);
715 }
b8cbc836 716 sendto(s, buf, sz, 0, (struct sockaddr *) &S, sizeof(S));
fb29421b 717 do {
7b724b86 718 fd_set R;
719 struct timeval to;
fb29421b 720 FD_ZERO(&R);
721 FD_SET(s, &R);
722 to.tv_sec = 10;
723 to.tv_usec = 0;
7b724b86 724 rl = select(s + 1, &R, NULL, NULL, &to);
725 } while (0);
726 if (rl < 1) {
727 printf("TIMEOUT\n");
728 continue;
729 }
fb29421b 730 memset(rbuf, '\0', 512);
731 rl = recv(s, rbuf, 512, 0);
732 {
0768dfce 733 unsigned short rid = 0;
fb29421b 734 int i;
735 int n;
b8cbc836 736 rfc1035_rr *answers = NULL;
737 n = rfc1035AnswersUnpack(rbuf,
fb29421b 738 rl,
b8cbc836 739 &answers,
740 &rid);
0768dfce 741 if (n < 0) {
fb29421b 742 printf("ERROR %d\n", rfc1035_errno);
0768dfce 743 } else if (rid != sid) {
744 printf("ERROR, ID mismatch (%#hx, %#hx)\n", sid, rid);
fb29421b 745 } else {
b8cbc836 746 printf("%d answers\n", n);
747 for (i = 0; i < n; i++) {
748 if (answers[i].type == RFC1035_TYPE_A) {
749 struct in_addr a;
750 memcpy(&a, answers[i].rdata, 4);
751 printf("A\t%d\t%s\n", answers[i].ttl, inet_ntoa(a));
752 } else if (answers[i].type == RFC1035_TYPE_PTR) {
753 char ptr[128];
754 strncpy(ptr, answers[i].rdata, answers[i].rdlength);
755 printf("PTR\t%d\t%s\n", answers[i].ttl, ptr);
756 } else {
757 fprintf(stderr, "can't print answer type %d\n",
758 (int) answers[i].type);
759 }
760 }
fb29421b 761 }
762 }
763 }
764 return 0;
765}
766#endif