]> git.ipfire.org Git - thirdparty/squid.git/blame - lib/rfc1035.c
Compare the query sesion of DNS responses to the actual query to ensure
[thirdparty/squid.git] / lib / rfc1035.c
CommitLineData
461eef68 1
7f3647d6 2/*
9e1f210d 3 * $Id: rfc1035.c,v 1.43 2005/05/10 10:09:32 hno 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"
ec7bade0 43#include "util.h"
fb29421b 44
45#if HAVE_STDIO_H
46#include <stdio.h>
47#endif
48#if HAVE_UNISTD_H
49#include <unistd.h>
50#endif
51#if HAVE_STDLIB_H
52#include <stdlib.h>
53#endif
54#if HAVE_MEMORY_H
55#include <memory.h>
56#endif
57#if HAVE_SYS_TYPES_H
58#include <sys/types.h>
59#endif
60#if HAVE_ASSERT_H
61#include <assert.h>
62#endif
63#if HAVE_NETINET_IN_H
64#include <netinet/in.h>
65#endif
66#if HAVE_ARPA_INET_H
67#include <arpa/inet.h>
68#endif
69#if HAVE_STRINGS_H
70#include <strings.h>
71#endif
72
7b724b86 73#include "rfc1035.h"
d86af726 74#include "snprintf.h"
fb29421b 75
76#define RFC1035_MAXLABELSZ 63
0768dfce 77#define rfc1035_unpack_error 15
78
79#if 0
80#define RFC1035_UNPACK_DEBUG fprintf(stderr, "unpack error at %s:%d\n", __FILE__,__LINE__)
81#else
82#define RFC1035_UNPACK_DEBUG (void)0
83#endif
84
fb29421b 85
fb29421b 86
87int rfc1035_errno;
7b724b86 88const char *rfc1035_error_message;
fb29421b 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 */
96static off_t
ec7bade0 97rfc1035HeaderPack(char *buf, size_t sz, rfc1035_message * 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 */
141static off_t
142rfc1035LabelPack(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 */
2d72d4fd 166static off_t
fb29421b 167rfc1035NamePack(char *buf, size_t sz, const char *name)
168{
169 off_t off = 0;
ec7bade0 170 char *copy = xstrdup(name);
fb29421b 171 char *t;
0a8e6ec2 172 /*
173 * NOTE: use of strtok here makes names like foo....com valid.
174 */
fb29421b 175 for (t = strtok(copy, "."); t; t = strtok(NULL, "."))
176 off += rfc1035LabelPack(buf + off, sz - off, t);
ec7bade0 177 xfree(copy);
fb29421b 178 off += rfc1035LabelPack(buf + off, sz - off, NULL);
179 assert(off <= sz);
180 return off;
181}
182
183/*
184 * rfc1035QuestionPack()
185 *
186 * Packs a QUESTION section of a message.
187 * Returns number of octets packed.
188 */
189static off_t
190rfc1035QuestionPack(char *buf,
191 size_t sz,
192 const char *name,
193 unsigned short type,
29b8d8d6 194 unsigned short _class)
fb29421b 195{
196 off_t off = 0;
197 unsigned short s;
198 off += rfc1035NamePack(buf + off, sz - off, name);
199 s = htons(type);
200 memcpy(buf + off, &s, sizeof(s));
201 off += sizeof(s);
29b8d8d6 202 s = htons(_class);
fb29421b 203 memcpy(buf + off, &s, sizeof(s));
204 off += sizeof(s);
205 assert(off <= sz);
206 return off;
207}
208
209/*
210 * rfc1035HeaderUnpack()
211 *
ec7bade0 212 * Unpacks a RFC1035 message header buffer into the header fields
213 * of the rfc1035_message structure.
0768dfce 214 *
215 * Updates the buffer offset, which is the same as number of
fb29421b 216 * octects unpacked since the header starts at offset 0.
0768dfce 217 *
218 * Returns 0 (success) or 1 (error)
fb29421b 219 */
0768dfce 220static int
ec7bade0 221rfc1035HeaderUnpack(const char *buf, size_t sz, off_t * off, rfc1035_message * h)
fb29421b 222{
223 unsigned short s;
224 unsigned short t;
0768dfce 225 assert(*off == 0);
226 /*
227 * The header is 12 octets. This is a bogus message if the size
228 * is less than that.
229 */
230 if (sz < 12)
231 return 1;
232 memcpy(&s, buf + (*off), sizeof(s));
233 (*off) += sizeof(s);
fb29421b 234 h->id = ntohs(s);
0768dfce 235 memcpy(&s, buf + (*off), sizeof(s));
236 (*off) += sizeof(s);
fb29421b 237 t = ntohs(s);
238 h->qr = (t >> 15) & 0x01;
239 h->opcode = (t >> 11) & 0x0F;
240 h->aa = (t >> 10) & 0x01;
c415c128 241 h->tc = (t >> 9) & 0x01;
fb29421b 242 h->rd = (t >> 8) & 0x01;
243 h->ra = (t >> 7) & 0x01;
0768dfce 244 /*
245 * We might want to check that the reserved 'Z' bits (6-4) are
246 * all zero as per RFC 1035. If not the message should be
247 * rejected.
248 */
fb29421b 249 h->rcode = t & 0x0F;
0768dfce 250 memcpy(&s, buf + (*off), sizeof(s));
251 (*off) += sizeof(s);
fb29421b 252 h->qdcount = ntohs(s);
0768dfce 253 memcpy(&s, buf + (*off), sizeof(s));
254 (*off) += sizeof(s);
fb29421b 255 h->ancount = ntohs(s);
0768dfce 256 memcpy(&s, buf + (*off), sizeof(s));
257 (*off) += sizeof(s);
fb29421b 258 h->nscount = ntohs(s);
0768dfce 259 memcpy(&s, buf + (*off), sizeof(s));
260 (*off) += sizeof(s);
fb29421b 261 h->arcount = ntohs(s);
0768dfce 262 assert((*off) == 12);
263 return 0;
fb29421b 264}
265
266/*
267 * rfc1035NameUnpack()
268 *
269 * Unpacks a Name in a message buffer into a char*.
270 * Note 'buf' points to the beginning of the whole message,
271 * 'off' points to the spot where the Name begins, and 'sz'
272 * is the size of the whole message. 'name' must be allocated
273 * by the caller.
274 *
275 * Supports the RFC1035 message compression through recursion.
276 *
0768dfce 277 * Updates the new buffer offset.
278 *
279 * Returns 0 (success) or 1 (error)
fb29421b 280 */
0768dfce 281static int
c837c655 282rfc1035NameUnpack(const char *buf, size_t sz, off_t * off, unsigned short *rdlength, char *name, size_t ns, int rdepth)
fb29421b 283{
284 off_t no = 0;
285 unsigned char c;
286 size_t len;
287 assert(ns > 0);
288 do {
0768dfce 289 assert((*off) < sz);
290 c = *(buf + (*off));
291 if (c > 191) {
c4eb7525 292 /* blasted compression */
fb29421b 293 unsigned short s;
294 off_t ptr;
db17c597 295 if (rdepth > 64) /* infinite pointer loop */
13c900c4 296 return 1;
0768dfce 297 memcpy(&s, buf + (*off), sizeof(s));
fb29421b 298 s = ntohs(s);
0768dfce 299 (*off) += sizeof(s);
300 /* Sanity check */
301 if ((*off) >= sz)
302 return 1;
fb29421b 303 ptr = s & 0x3FFF;
0768dfce 304 /* Make sure the pointer is inside this message */
305 if (ptr >= sz)
306 return 1;
c837c655 307 return rfc1035NameUnpack(buf, sz, &ptr, rdlength, name + no, ns - no, rdepth + 1);
26527d3b 308 } else if (c > RFC1035_MAXLABELSZ) {
0768dfce 309 /*
310 * "(The 10 and 01 combinations are reserved for future use.)"
311 */
312 return 1;
fb29421b 313 } else {
0768dfce 314 (*off)++;
fb29421b 315 len = (size_t) c;
316 if (len == 0)
317 break;
13c900c4 318 if (len > (ns - no - 1)) /* label won't fit */
319 return 1;
1a8a1b50 320 if ((*off) + len >= sz) /* message is too short */
0768dfce 321 return 1;
322 memcpy(name + no, buf + (*off), len);
323 (*off) += len;
fb29421b 324 no += len;
325 *(name + (no++)) = '.';
c837c655 326 if (rdlength)
327 *rdlength += len + 1;
fb29421b 328 }
13c900c4 329 } while (c > 0 && no < ns);
4775d711 330 if (no)
331 *(name + no - 1) = '\0';
332 else
333 *name = '\0';
0768dfce 334 /* make sure we didn't allow someone to overflow the name buffer */
fb29421b 335 assert(no <= ns);
0768dfce 336 return 0;
fb29421b 337}
338
339/*
340 * rfc1035RRUnpack()
341 *
342 * Unpacks a RFC1035 Resource Record into 'RR' from a message buffer.
343 * The caller must free RR->rdata!
0768dfce 344 *
345 * Updates the new message buffer offset.
346 *
347 * Returns 0 (success) or 1 (error)
fb29421b 348 */
0768dfce 349static int
350rfc1035RRUnpack(const char *buf, size_t sz, off_t * off, rfc1035_rr * RR)
fb29421b 351{
352 unsigned short s;
353 unsigned int i;
c837c655 354 unsigned short rdlength;
26527d3b 355 off_t rdata_off;
c837c655 356 if (rfc1035NameUnpack(buf, sz, off, NULL, RR->name, RFC1035_MAXHOSTNAMESZ, 0)) {
0768dfce 357 RFC1035_UNPACK_DEBUG;
358 memset(RR, '\0', sizeof(*RR));
359 return 1;
360 }
361 /*
362 * Make sure the remaining message has enough octets for the
363 * rest of the RR fields.
364 */
365 if ((*off) + 10 > sz) {
366 RFC1035_UNPACK_DEBUG;
367 memset(RR, '\0', sizeof(*RR));
368 return 1;
369 }
370 memcpy(&s, buf + (*off), sizeof(s));
371 (*off) += sizeof(s);
fb29421b 372 RR->type = ntohs(s);
0768dfce 373 memcpy(&s, buf + (*off), sizeof(s));
374 (*off) += sizeof(s);
29b8d8d6 375 RR->_class = ntohs(s);
0768dfce 376 memcpy(&i, buf + (*off), sizeof(i));
377 (*off) += sizeof(i);
fb29421b 378 RR->ttl = ntohl(i);
0768dfce 379 memcpy(&s, buf + (*off), sizeof(s));
380 (*off) += sizeof(s);
c837c655 381 rdlength = ntohs(s);
382 if ((*off) + rdlength > sz) {
c415c128 383 /*
384 * We got a truncated packet. 'dnscache' truncates UDP
0768dfce 385 * replies at 512 octets, as per RFC 1035.
c415c128 386 */
0768dfce 387 RFC1035_UNPACK_DEBUG;
a60011f4 388 memset(RR, '\0', sizeof(*RR));
0768dfce 389 return 1;
c415c128 390 }
c837c655 391 RR->rdlength = rdlength;
b8cbc836 392 switch (RR->type) {
393 case RFC1035_TYPE_PTR:
ec7bade0 394 RR->rdata = xmalloc(RFC1035_MAXHOSTNAMESZ);
26527d3b 395 rdata_off = *off;
9e1f210d 396 RR->rdlength = 0; /* Filled in by rfc1035NameUnpack */
c837c655 397 if (rfc1035NameUnpack(buf, sz, &rdata_off, &RR->rdlength, RR->rdata, RFC1035_MAXHOSTNAMESZ, 0))
0768dfce 398 return 1;
914eac3d 399 if (rdata_off > ((*off) + rdlength)) {
26527d3b 400 /*
401 * This probably doesn't happen for valid packets, but
402 * I want to make sure that NameUnpack doesn't go beyond
403 * the RDATA area.
404 */
405 RFC1035_UNPACK_DEBUG;
9e1f210d 406 xfree(RR->rdata);
26527d3b 407 memset(RR, '\0', sizeof(*RR));
408 return 1;
409 }
b8cbc836 410 break;
411 case RFC1035_TYPE_A:
412 default:
ec7bade0 413 RR->rdata = xmalloc(rdlength);
c837c655 414 memcpy(RR->rdata, buf + (*off), rdlength);
b8cbc836 415 break;
416 }
c837c655 417 (*off) += rdlength;
0768dfce 418 assert((*off) <= sz);
419 return 0;
fb29421b 420}
421
76cb2b26 422static void
423rfc1035SetErrno(int n)
424{
425 switch (rfc1035_errno = n) {
426 case 0:
427 rfc1035_error_message = "No error condition";
428 break;
429 case 1:
430 rfc1035_error_message = "Format Error: The name server was "
431 "unable to interpret the query.";
432 break;
433 case 2:
434 rfc1035_error_message = "Server Failure: The name server was "
435 "unable to process this query.";
436 break;
437 case 3:
438 rfc1035_error_message = "Name Error: The domain name does "
439 "not exist.";
440 break;
441 case 4:
442 rfc1035_error_message = "Not Implemented: The name server does "
443 "not support the requested kind of query.";
444 break;
445 case 5:
446 rfc1035_error_message = "Refused: The name server refuses to "
447 "perform the specified operation.";
448 break;
0768dfce 449 case rfc1035_unpack_error:
450 rfc1035_error_message = "The DNS reply message is corrupt or could "
451 "not be safely parsed.";
452 break;
76cb2b26 453 default:
454 rfc1035_error_message = "Unknown Error";
455 break;
456 }
457}
458
ec7bade0 459static void
7b724b86 460rfc1035RRDestroy(rfc1035_rr * rr, int n)
461{
462 if (rr == NULL)
463 return;
464 assert(n > 0);
465 while (n--) {
466 if (rr[n].rdata)
ec7bade0 467 xfree(rr[n].rdata);
7b724b86 468 }
ec7bade0 469 xfree(rr);
7b724b86 470}
471
0768dfce 472/*
ec7bade0 473 * rfc1035QueryUnpack()
474 *
475 * Unpacks a RFC1035 Query Record into 'query' from a message buffer.
476 *
477 * Updates the new message buffer offset.
478 *
479 * Returns 0 (success) or 1 (error)
480 */
481static int
482rfc1035QueryUnpack(const char *buf, size_t sz, off_t * off, rfc1035_query * query)
483{
484 unsigned short s;
485 if (rfc1035NameUnpack(buf, sz, off, NULL, query->name, RFC1035_MAXHOSTNAMESZ, 0)) {
486 RFC1035_UNPACK_DEBUG;
487 memset(query, '\0', sizeof(*query));
488 return 1;
489 }
490 if (*off + 4 > sz) {
491 RFC1035_UNPACK_DEBUG;
492 memset(query, '\0', sizeof(*query));
493 return 1;
494 }
495 memcpy(&s, buf + *off, 2);
496 *off += 2;
ec7bade0 497 query->qtype = ntohs(s);
498 memcpy(&s, buf + *off, 2);
499 *off += 2;
9e1f210d 500 query->qclass = ntohs(s);
ec7bade0 501 return 0;
502}
503
9e1f210d 504void
505rfc1035MessageDestroy(rfc1035_message * msg)
ec7bade0 506{
507 if (!msg)
508 return;
509 if (msg->query)
510 xfree(msg->query);
511 if (msg->answer)
512 rfc1035RRDestroy(msg->answer, msg->ancount);
513 xfree(msg);
514}
515
9e1f210d 516/*
517 * rfc1035QueryCompare()
518 *
519 * Compares two rfc1035_query entries
520 *
521 * Returns 0 (equal) or !=0 (different)
522 */
523int
524rfc1035QueryCompare(const rfc1035_query * a, const rfc1035_query * b)
525{
526 if (a->qtype != b->qtype)
527 return 1;
528 if (a->qclass != b->qclass)
529 return 1;
530 return strcmp(a->name, b->name);
531}
532
ec7bade0 533/*
534 * rfc1035MessageUnpack()
0768dfce 535 *
536 * Takes the contents of a DNS reply and fills in an array
537 * of resource record structures. The records array is allocated
538 * here, and should be freed by calling rfc1035RRDestroy().
539 *
540 * Returns number of records unpacked, zero if DNS reply indicates
541 * zero answers, or an error number < 0.
542 */
543
fb29421b 544int
ec7bade0 545rfc1035MessageUnpack(const char *buf,
7b724b86 546 size_t sz,
ec7bade0 547 rfc1035_message ** answer)
fb29421b 548{
0768dfce 549 off_t off = 0;
fb29421b 550 int i;
7b724b86 551 int nr = 0;
ec7bade0 552 rfc1035_message *msg;
7b724b86 553 rfc1035_rr *recs;
ec7bade0 554 rfc1035_query *querys;
555 msg = xcalloc(1, sizeof(*msg));
556 if (rfc1035HeaderUnpack(buf + off, sz - off, &off, msg)) {
0768dfce 557 RFC1035_UNPACK_DEBUG;
558 rfc1035SetErrno(rfc1035_unpack_error);
ec7bade0 559 xfree(msg);
0768dfce 560 return -rfc1035_unpack_error;
561 }
7b724b86 562 rfc1035_errno = 0;
563 rfc1035_error_message = NULL;
ec7bade0 564 if (msg->rcode) {
0768dfce 565 RFC1035_UNPACK_DEBUG;
ec7bade0 566 rfc1035SetErrno((int) msg->rcode);
567 xfree(msg);
fb29421b 568 return -rfc1035_errno;
569 }
ec7bade0 570 i = (int) msg->qdcount;
571 if (i != 1) {
572 /* This can not be an answer to our queries.. */
573 RFC1035_UNPACK_DEBUG;
574 rfc1035SetErrno(rfc1035_unpack_error);
575 xfree(msg);
576 return -rfc1035_unpack_error;
577 }
9e1f210d 578 querys = msg->query = xcalloc((int) msg->qdcount, sizeof(*querys));
579 for (i = 0; i < (int) msg->qdcount; i++) {
ec7bade0 580 if (rfc1035QueryUnpack(buf, sz, &off, &querys[i])) {
0768dfce 581 RFC1035_UNPACK_DEBUG;
582 rfc1035SetErrno(rfc1035_unpack_error);
ec7bade0 583 rfc1035MessageDestroy(msg);
0768dfce 584 return -rfc1035_unpack_error;
585 }
fb29421b 586 }
ec7bade0 587 *answer = msg;
588 if (msg->ancount == 0)
706d89bc 589 return 0;
9e1f210d 590 recs = msg->answer = xcalloc((int) msg->ancount, sizeof(*recs));
591 for (i = 0; i < (int) msg->ancount; i++) {
0768dfce 592 if (off >= sz) { /* corrupt packet */
593 RFC1035_UNPACK_DEBUG;
594 break;
595 }
596 if (rfc1035RRUnpack(buf, sz, &off, &recs[i])) { /* corrupt RR */
597 RFC1035_UNPACK_DEBUG;
c415c128 598 break;
0768dfce 599 }
7b724b86 600 nr++;
fb29421b 601 }
0768dfce 602 if (nr == 0) {
603 /*
604 * we expected to unpack some answers (ancount != 0), but
605 * didn't actually get any.
606 */
ec7bade0 607 rfc1035MessageDestroy(msg);
608 *answer = NULL;
0768dfce 609 rfc1035SetErrno(rfc1035_unpack_error);
610 return -rfc1035_unpack_error;
611 }
7b724b86 612 return nr;
fb29421b 613}
614
615/*
b8cbc836 616 * rfc1035BuildAQuery()
fb29421b 617 *
618 * Builds a message buffer with a QUESTION to lookup A records
619 * for a hostname. Caller must allocate 'buf' which should
620 * probably be at least 512 octets. The 'szp' initially
621 * specifies the size of the buffer, on return it contains
622 * the size of the message (i.e. how much to write).
108d67a0 623 * Returns the size of the query
fb29421b 624 */
108d67a0 625ssize_t
9e1f210d 626rfc1035BuildAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query * query)
fb29421b 627{
ec7bade0 628 static rfc1035_message h;
2d72d4fd 629 size_t offset = 0;
fb29421b 630 memset(&h, '\0', sizeof(h));
108d67a0 631 h.id = qid;
fb29421b 632 h.qr = 0;
633 h.rd = 1;
634 h.opcode = 0; /* QUERY */
635 h.qdcount = (unsigned int) 1;
636 offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
637 offset += rfc1035QuestionPack(buf + offset,
638 sz - offset,
639 hostname,
640 RFC1035_TYPE_A,
641 RFC1035_CLASS_IN);
9e1f210d 642 if (query) {
643 query->qtype = RFC1035_TYPE_A;
644 query->qclass = RFC1035_CLASS_IN;
645 xstrncpy(query->name, hostname, sizeof(query->name));
646 }
fb29421b 647 assert(offset <= sz);
108d67a0 648 return offset;
fb29421b 649}
650
b8cbc836 651/*
652 * rfc1035BuildPTRQuery()
653 *
654 * Builds a message buffer with a QUESTION to lookup PTR records
655 * for an address. Caller must allocate 'buf' which should
656 * probably be at least 512 octets. The 'szp' initially
657 * specifies the size of the buffer, on return it contains
658 * the size of the message (i.e. how much to write).
659 * Return value is the query ID.
660 */
108d67a0 661ssize_t
9e1f210d 662rfc1035BuildPTRQuery(const struct IN_ADDR addr, char *buf, size_t sz, unsigned short qid, rfc1035_query * query)
b8cbc836 663{
ec7bade0 664 static rfc1035_message h;
2d72d4fd 665 size_t offset = 0;
b8cbc836 666 static char rev[32];
667 unsigned int i;
668 memset(&h, '\0', sizeof(h));
d0017a72 669 i = (unsigned int) ntohl(addr.s_addr);
670 snprintf(rev, 32, "%u.%u.%u.%u.in-addr.arpa.",
671 i & 255,
b8cbc836 672 (i >> 8) & 255,
d0017a72 673 (i >> 16) & 255,
674 (i >> 24) & 255);
108d67a0 675 h.id = qid;
b8cbc836 676 h.qr = 0;
677 h.rd = 1;
678 h.opcode = 0; /* QUERY */
679 h.qdcount = (unsigned int) 1;
680 offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
681 offset += rfc1035QuestionPack(buf + offset,
682 sz - offset,
683 rev,
684 RFC1035_TYPE_PTR,
685 RFC1035_CLASS_IN);
9e1f210d 686 if (query) {
687 query->qtype = RFC1035_TYPE_PTR;
688 query->qclass = RFC1035_CLASS_IN;
689 xstrncpy(query->name, rev, sizeof(query->name));
690 }
b8cbc836 691 assert(offset <= sz);
108d67a0 692 return offset;
b8cbc836 693}
694
558be27a 695/*
696 * We're going to retry a former query, but we
697 * just need a new ID for it. Lucky for us ID
698 * is the first field in the message buffer.
699 */
108d67a0 700void
701rfc1035SetQueryID(char *buf, unsigned short qid)
558be27a 702{
558be27a 703 unsigned short s = htons(qid);
704 memcpy(buf, &s, sizeof(s));
558be27a 705}
706
fb29421b 707#if DRIVER
b8cbc836 708#include <sys/socket.h>
709#include <sys/time.h>
fb29421b 710int
711main(int argc, char *argv[])
712{
fb29421b 713 char input[512];
714 char buf[512];
715 char rbuf[512];
716 size_t sz = 512;
717 unsigned short sid;
fb29421b 718 int s;
719 int rl;
720 struct sockaddr_in S;
0768dfce 721 if (3 != argc) {
722 fprintf(stderr, "usage: %s ip port\n", argv[0]);
723 return 1;
724 }
fb29421b 725 setbuf(stdout, NULL);
726 setbuf(stderr, NULL);
727 s = socket(PF_INET, SOCK_DGRAM, 0);
728 if (s < 0) {
729 perror("socket");
730 return 1;
731 }
0768dfce 732 memset(&S, '\0', sizeof(S));
733 S.sin_family = AF_INET;
734 S.sin_port = htons(atoi(argv[2]));
735 S.sin_addr.s_addr = inet_addr(argv[1]);
fb29421b 736 while (fgets(input, 512, stdin)) {
ddfcbc22 737 struct IN_ADDR junk;
fb29421b 738 strtok(input, "\r\n");
739 memset(buf, '\0', 512);
b8cbc836 740 sz = 512;
741 if (inet_aton(input, &junk)) {
742 sid = rfc1035BuildPTRQuery(junk, buf, &sz);
743 } else {
744 sid = rfc1035BuildAQuery(input, buf, &sz);
745 }
b8cbc836 746 sendto(s, buf, sz, 0, (struct sockaddr *) &S, sizeof(S));
fb29421b 747 do {
7b724b86 748 fd_set R;
749 struct timeval to;
fb29421b 750 FD_ZERO(&R);
751 FD_SET(s, &R);
752 to.tv_sec = 10;
753 to.tv_usec = 0;
7b724b86 754 rl = select(s + 1, &R, NULL, NULL, &to);
755 } while (0);
756 if (rl < 1) {
757 printf("TIMEOUT\n");
758 continue;
759 }
fb29421b 760 memset(rbuf, '\0', 512);
761 rl = recv(s, rbuf, 512, 0);
762 {
0768dfce 763 unsigned short rid = 0;
fb29421b 764 int i;
765 int n;
b8cbc836 766 rfc1035_rr *answers = NULL;
767 n = rfc1035AnswersUnpack(rbuf,
fb29421b 768 rl,
b8cbc836 769 &answers,
770 &rid);
0768dfce 771 if (n < 0) {
fb29421b 772 printf("ERROR %d\n", rfc1035_errno);
0768dfce 773 } else if (rid != sid) {
774 printf("ERROR, ID mismatch (%#hx, %#hx)\n", sid, rid);
fb29421b 775 } else {
b8cbc836 776 printf("%d answers\n", n);
777 for (i = 0; i < n; i++) {
778 if (answers[i].type == RFC1035_TYPE_A) {
ddfcbc22 779 struct IN_ADDR a;
b8cbc836 780 memcpy(&a, answers[i].rdata, 4);
781 printf("A\t%d\t%s\n", answers[i].ttl, inet_ntoa(a));
782 } else if (answers[i].type == RFC1035_TYPE_PTR) {
783 char ptr[128];
784 strncpy(ptr, answers[i].rdata, answers[i].rdlength);
785 printf("PTR\t%d\t%s\n", answers[i].ttl, ptr);
786 } else {
787 fprintf(stderr, "can't print answer type %d\n",
788 (int) answers[i].type);
789 }
790 }
fb29421b 791 }
792 }
793 }
794 return 0;
795}
796#endif