]> git.ipfire.org Git - thirdparty/squid.git/blame - lib/rfc1035.c
Add check for cast error in AuthBasicUserRequest::authenticate()
[thirdparty/squid.git] / lib / rfc1035.c
CommitLineData
461eef68 1
7f3647d6 2/*
577090e4 3 * $Id: rfc1035.c,v 1.45 2005/05/11 14:26:52 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 */
fc0f8140 96static int
ec7bade0 97rfc1035HeaderPack(char *buf, size_t sz, rfc1035_message * hdr)
fb29421b 98{
fc0f8140 99 int off = 0;
fb29421b 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 */
fc0f8140 141static int
fb29421b 142rfc1035LabelPack(char *buf, size_t sz, const char *label)
143{
fc0f8140 144 int off = 0;
fb29421b 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 */
fc0f8140 166static int
fb29421b 167rfc1035NamePack(char *buf, size_t sz, const char *name)
168{
fc0f8140 169 int 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 */
fc0f8140 189static int
fb29421b 190rfc1035QuestionPack(char *buf,
191 size_t sz,
192 const char *name,
193 unsigned short type,
29b8d8d6 194 unsigned short _class)
fb29421b 195{
fc0f8140 196 int off = 0;
fb29421b 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
fc0f8140 221rfc1035HeaderUnpack(const char *buf, size_t sz, int *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
fc0f8140 282rfc1035NameUnpack(const char *buf, size_t sz, int *off, unsigned short *rdlength, char *name, size_t ns, int rdepth)
fb29421b 283{
fc0f8140 284 int no = 0;
fb29421b 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;
fc0f8140 294 int 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
fc0f8140 350rfc1035RRUnpack(const char *buf, size_t sz, int *off, rfc1035_rr * RR)
fb29421b 351{
352 unsigned short s;
353 unsigned int i;
c837c655 354 unsigned short rdlength;
fc0f8140 355 int 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
fc0f8140 482rfc1035QueryUnpack(const char *buf, size_t sz, int *off, rfc1035_query * query)
ec7bade0 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
fc0f8140 504void
9e1f210d 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{
577090e4 526 size_t la, lb;
9e1f210d 527 if (a->qtype != b->qtype)
528 return 1;
529 if (a->qclass != b->qclass)
530 return 1;
577090e4 531 la = strlen(a->name);
532 lb = strlen(b->name);
533 if (la != lb) {
534 /* Trim root label(s) */
535 while (la > 0 && a->name[la - 1] == '.')
536 la--;
537 while (lb > 0 && b->name[lb - 1] == '.')
538 lb--;
539 }
540 if (la != lb)
541 return 1;
542
543 return strncasecmp(a->name, b->name, la);
9e1f210d 544}
545
ec7bade0 546/*
547 * rfc1035MessageUnpack()
0768dfce 548 *
549 * Takes the contents of a DNS reply and fills in an array
550 * of resource record structures. The records array is allocated
551 * here, and should be freed by calling rfc1035RRDestroy().
552 *
553 * Returns number of records unpacked, zero if DNS reply indicates
554 * zero answers, or an error number < 0.
555 */
556
fb29421b 557int
ec7bade0 558rfc1035MessageUnpack(const char *buf,
7b724b86 559 size_t sz,
ec7bade0 560 rfc1035_message ** answer)
fb29421b 561{
fc0f8140 562 int off = 0;
fb29421b 563 int i;
7b724b86 564 int nr = 0;
ec7bade0 565 rfc1035_message *msg;
7b724b86 566 rfc1035_rr *recs;
ec7bade0 567 rfc1035_query *querys;
568 msg = xcalloc(1, sizeof(*msg));
569 if (rfc1035HeaderUnpack(buf + off, sz - off, &off, msg)) {
0768dfce 570 RFC1035_UNPACK_DEBUG;
571 rfc1035SetErrno(rfc1035_unpack_error);
ec7bade0 572 xfree(msg);
0768dfce 573 return -rfc1035_unpack_error;
574 }
7b724b86 575 rfc1035_errno = 0;
576 rfc1035_error_message = NULL;
ec7bade0 577 i = (int) msg->qdcount;
578 if (i != 1) {
579 /* This can not be an answer to our queries.. */
580 RFC1035_UNPACK_DEBUG;
581 rfc1035SetErrno(rfc1035_unpack_error);
582 xfree(msg);
583 return -rfc1035_unpack_error;
584 }
9e1f210d 585 querys = msg->query = xcalloc((int) msg->qdcount, sizeof(*querys));
586 for (i = 0; i < (int) msg->qdcount; i++) {
ec7bade0 587 if (rfc1035QueryUnpack(buf, sz, &off, &querys[i])) {
0768dfce 588 RFC1035_UNPACK_DEBUG;
589 rfc1035SetErrno(rfc1035_unpack_error);
ec7bade0 590 rfc1035MessageDestroy(msg);
0768dfce 591 return -rfc1035_unpack_error;
592 }
fb29421b 593 }
ec7bade0 594 *answer = msg;
577090e4 595 if (msg->rcode) {
596 RFC1035_UNPACK_DEBUG;
597 rfc1035SetErrno((int) msg->rcode);
598 return -rfc1035_errno;
599 }
ec7bade0 600 if (msg->ancount == 0)
706d89bc 601 return 0;
9e1f210d 602 recs = msg->answer = xcalloc((int) msg->ancount, sizeof(*recs));
603 for (i = 0; i < (int) msg->ancount; i++) {
0768dfce 604 if (off >= sz) { /* corrupt packet */
605 RFC1035_UNPACK_DEBUG;
606 break;
607 }
608 if (rfc1035RRUnpack(buf, sz, &off, &recs[i])) { /* corrupt RR */
609 RFC1035_UNPACK_DEBUG;
c415c128 610 break;
0768dfce 611 }
7b724b86 612 nr++;
fb29421b 613 }
0768dfce 614 if (nr == 0) {
615 /*
616 * we expected to unpack some answers (ancount != 0), but
617 * didn't actually get any.
618 */
ec7bade0 619 rfc1035MessageDestroy(msg);
620 *answer = NULL;
0768dfce 621 rfc1035SetErrno(rfc1035_unpack_error);
622 return -rfc1035_unpack_error;
623 }
7b724b86 624 return nr;
fb29421b 625}
626
627/*
b8cbc836 628 * rfc1035BuildAQuery()
fb29421b 629 *
630 * Builds a message buffer with a QUESTION to lookup A records
631 * for a hostname. Caller must allocate 'buf' which should
632 * probably be at least 512 octets. The 'szp' initially
633 * specifies the size of the buffer, on return it contains
634 * the size of the message (i.e. how much to write).
108d67a0 635 * Returns the size of the query
fb29421b 636 */
108d67a0 637ssize_t
9e1f210d 638rfc1035BuildAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query * query)
fb29421b 639{
ec7bade0 640 static rfc1035_message h;
2d72d4fd 641 size_t offset = 0;
fb29421b 642 memset(&h, '\0', sizeof(h));
108d67a0 643 h.id = qid;
fb29421b 644 h.qr = 0;
645 h.rd = 1;
646 h.opcode = 0; /* QUERY */
647 h.qdcount = (unsigned int) 1;
648 offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
649 offset += rfc1035QuestionPack(buf + offset,
650 sz - offset,
651 hostname,
652 RFC1035_TYPE_A,
653 RFC1035_CLASS_IN);
9e1f210d 654 if (query) {
655 query->qtype = RFC1035_TYPE_A;
656 query->qclass = RFC1035_CLASS_IN;
657 xstrncpy(query->name, hostname, sizeof(query->name));
658 }
fb29421b 659 assert(offset <= sz);
108d67a0 660 return offset;
fb29421b 661}
662
b8cbc836 663/*
664 * rfc1035BuildPTRQuery()
665 *
666 * Builds a message buffer with a QUESTION to lookup PTR records
667 * for an address. Caller must allocate 'buf' which should
668 * probably be at least 512 octets. The 'szp' initially
669 * specifies the size of the buffer, on return it contains
670 * the size of the message (i.e. how much to write).
fc0f8140 671 * Returns the size of the query
b8cbc836 672 */
108d67a0 673ssize_t
9e1f210d 674rfc1035BuildPTRQuery(const struct IN_ADDR addr, char *buf, size_t sz, unsigned short qid, rfc1035_query * query)
b8cbc836 675{
ec7bade0 676 static rfc1035_message h;
2d72d4fd 677 size_t offset = 0;
b8cbc836 678 static char rev[32];
679 unsigned int i;
680 memset(&h, '\0', sizeof(h));
d0017a72 681 i = (unsigned int) ntohl(addr.s_addr);
682 snprintf(rev, 32, "%u.%u.%u.%u.in-addr.arpa.",
683 i & 255,
b8cbc836 684 (i >> 8) & 255,
d0017a72 685 (i >> 16) & 255,
686 (i >> 24) & 255);
108d67a0 687 h.id = qid;
b8cbc836 688 h.qr = 0;
689 h.rd = 1;
690 h.opcode = 0; /* QUERY */
691 h.qdcount = (unsigned int) 1;
692 offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
693 offset += rfc1035QuestionPack(buf + offset,
694 sz - offset,
695 rev,
696 RFC1035_TYPE_PTR,
697 RFC1035_CLASS_IN);
9e1f210d 698 if (query) {
699 query->qtype = RFC1035_TYPE_PTR;
700 query->qclass = RFC1035_CLASS_IN;
701 xstrncpy(query->name, rev, sizeof(query->name));
702 }
b8cbc836 703 assert(offset <= sz);
108d67a0 704 return offset;
b8cbc836 705}
706
558be27a 707/*
708 * We're going to retry a former query, but we
709 * just need a new ID for it. Lucky for us ID
710 * is the first field in the message buffer.
711 */
108d67a0 712void
713rfc1035SetQueryID(char *buf, unsigned short qid)
558be27a 714{
558be27a 715 unsigned short s = htons(qid);
716 memcpy(buf, &s, sizeof(s));
558be27a 717}
718
fb29421b 719#if DRIVER
b8cbc836 720#include <sys/socket.h>
721#include <sys/time.h>
fb29421b 722int
723main(int argc, char *argv[])
724{
fb29421b 725 char input[512];
726 char buf[512];
727 char rbuf[512];
728 size_t sz = 512;
729 unsigned short sid;
fb29421b 730 int s;
731 int rl;
732 struct sockaddr_in S;
0768dfce 733 if (3 != argc) {
734 fprintf(stderr, "usage: %s ip port\n", argv[0]);
735 return 1;
736 }
fb29421b 737 setbuf(stdout, NULL);
738 setbuf(stderr, NULL);
739 s = socket(PF_INET, SOCK_DGRAM, 0);
740 if (s < 0) {
741 perror("socket");
742 return 1;
743 }
0768dfce 744 memset(&S, '\0', sizeof(S));
745 S.sin_family = AF_INET;
746 S.sin_port = htons(atoi(argv[2]));
747 S.sin_addr.s_addr = inet_addr(argv[1]);
fb29421b 748 while (fgets(input, 512, stdin)) {
ddfcbc22 749 struct IN_ADDR junk;
fb29421b 750 strtok(input, "\r\n");
751 memset(buf, '\0', 512);
b8cbc836 752 sz = 512;
753 if (inet_aton(input, &junk)) {
754 sid = rfc1035BuildPTRQuery(junk, buf, &sz);
755 } else {
756 sid = rfc1035BuildAQuery(input, buf, &sz);
757 }
b8cbc836 758 sendto(s, buf, sz, 0, (struct sockaddr *) &S, sizeof(S));
fb29421b 759 do {
7b724b86 760 fd_set R;
761 struct timeval to;
fb29421b 762 FD_ZERO(&R);
763 FD_SET(s, &R);
764 to.tv_sec = 10;
765 to.tv_usec = 0;
7b724b86 766 rl = select(s + 1, &R, NULL, NULL, &to);
767 } while (0);
768 if (rl < 1) {
769 printf("TIMEOUT\n");
770 continue;
771 }
fb29421b 772 memset(rbuf, '\0', 512);
773 rl = recv(s, rbuf, 512, 0);
774 {
0768dfce 775 unsigned short rid = 0;
fb29421b 776 int i;
777 int n;
b8cbc836 778 rfc1035_rr *answers = NULL;
779 n = rfc1035AnswersUnpack(rbuf,
fb29421b 780 rl,
b8cbc836 781 &answers,
782 &rid);
0768dfce 783 if (n < 0) {
fb29421b 784 printf("ERROR %d\n", rfc1035_errno);
0768dfce 785 } else if (rid != sid) {
786 printf("ERROR, ID mismatch (%#hx, %#hx)\n", sid, rid);
fb29421b 787 } else {
b8cbc836 788 printf("%d answers\n", n);
789 for (i = 0; i < n; i++) {
790 if (answers[i].type == RFC1035_TYPE_A) {
ddfcbc22 791 struct IN_ADDR a;
b8cbc836 792 memcpy(&a, answers[i].rdata, 4);
793 printf("A\t%d\t%s\n", answers[i].ttl, inet_ntoa(a));
794 } else if (answers[i].type == RFC1035_TYPE_PTR) {
795 char ptr[128];
796 strncpy(ptr, answers[i].rdata, answers[i].rdlength);
797 printf("PTR\t%d\t%s\n", answers[i].ttl, ptr);
798 } else {
799 fprintf(stderr, "can't print answer type %d\n",
800 (int) answers[i].type);
801 }
802 }
fb29421b 803 }
804 }
805 }
806 return 0;
807}
808#endif