]> git.ipfire.org Git - thirdparty/squid.git/blame - lib/rfc1035.c
Boilerplate: update copyright blurbs on lib/snmplib
[thirdparty/squid.git] / lib / rfc1035.c
CommitLineData
7f3647d6 1/*
7f3647d6 2 * Low level DNS protocol routines
3 * AUTHOR: Duane Wessels
4 *
2b6662ba 5 * SQUID Web Proxy Cache http://www.squid-cache.org/
7f3647d6 6 * ----------------------------------------------------------
7 *
2b6662ba 8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
7f3647d6 16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
26ac0430 21 *
7f3647d6 22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26ac0430 26 *
7f3647d6 27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
30 *
31 */
32
c415c128 33/*
34 * KNOWN BUGS:
26ac0430 35 *
c415c128 36 * UDP replies with TC set should be retried via TCP
37 */
38
f7f3304a 39#include "squid.h"
ec7bade0 40#include "util.h"
fb29421b 41
a05af879
FC
42#if HAVE_STRING_H
43#include <string.h>
44#endif
fb29421b 45#if HAVE_UNISTD_H
46#include <unistd.h>
47#endif
fb29421b 48#if HAVE_MEMORY_H
49#include <memory.h>
50#endif
fb29421b 51#if HAVE_ASSERT_H
52#include <assert.h>
53#endif
54#if HAVE_NETINET_IN_H
55#include <netinet/in.h>
56#endif
57#if HAVE_ARPA_INET_H
58#include <arpa/inet.h>
59#endif
60#if HAVE_STRINGS_H
61#include <strings.h>
62#endif
63
7b724b86 64#include "rfc1035.h"
e210930b 65#include "rfc2671.h"
fb29421b 66
67#define RFC1035_MAXLABELSZ 63
0768dfce 68#define rfc1035_unpack_error 15
69
70#if 0
71#define RFC1035_UNPACK_DEBUG fprintf(stderr, "unpack error at %s:%d\n", __FILE__,__LINE__)
72#else
73#define RFC1035_UNPACK_DEBUG (void)0
74#endif
75
fb29421b 76/*
77 * rfc1035HeaderPack()
26ac0430 78 *
7b724b86 79 * Packs a rfc1035_header structure into a buffer.
fb29421b 80 * Returns number of octets packed (should always be 12)
81 */
64b636b9 82int
ec7bade0 83rfc1035HeaderPack(char *buf, size_t sz, rfc1035_message * hdr)
fb29421b 84{
fc0f8140 85 int off = 0;
fb29421b 86 unsigned short s;
87 unsigned short t;
88 assert(sz >= 12);
89 s = htons(hdr->id);
90 memcpy(buf + off, &s, sizeof(s));
91 off += sizeof(s);
92 t = 0;
93 t |= hdr->qr << 15;
94 t |= (hdr->opcode << 11);
95 t |= (hdr->aa << 10);
96 t |= (hdr->tc << 9);
97 t |= (hdr->rd << 8);
98 t |= (hdr->ra << 7);
99 t |= hdr->rcode;
100 s = htons(t);
101 memcpy(buf + off, &s, sizeof(s));
102 off += sizeof(s);
103 s = htons(hdr->qdcount);
104 memcpy(buf + off, &s, sizeof(s));
105 off += sizeof(s);
106 s = htons(hdr->ancount);
107 memcpy(buf + off, &s, sizeof(s));
108 off += sizeof(s);
109 s = htons(hdr->nscount);
110 memcpy(buf + off, &s, sizeof(s));
111 off += sizeof(s);
112 s = htons(hdr->arcount);
113 memcpy(buf + off, &s, sizeof(s));
114 off += sizeof(s);
115 assert(off == 12);
116 return off;
117}
118
119/*
120 * rfc1035LabelPack()
26ac0430 121 *
fb29421b 122 * Packs a label into a buffer. The format of
123 * a label is one octet specifying the number of character
124 * bytes to follow. Labels must be smaller than 64 octets.
125 * Returns number of octets packed.
126 */
fc0f8140 127static int
fb29421b 128rfc1035LabelPack(char *buf, size_t sz, const char *label)
129{
fc0f8140 130 int off = 0;
fb29421b 131 size_t len = label ? strlen(label) : 0;
132 if (label)
26ac0430 133 assert(!strchr(label, '.'));
fb29421b 134 if (len > RFC1035_MAXLABELSZ)
26ac0430 135 len = RFC1035_MAXLABELSZ;
fb29421b 136 assert(sz >= len + 1);
137 *(buf + off) = (char) len;
138 off++;
139 memcpy(buf + off, label, len);
140 off += len;
141 return off;
142}
143
144/*
145 * rfc1035NamePack()
26ac0430 146 *
fb29421b 147 * Packs a name into a buffer. Names are packed as a
148 * sequence of labels, terminated with NULL label.
149 * Note message compression is not supported here.
150 * Returns number of octets packed.
151 */
fc0f8140 152static int
fb29421b 153rfc1035NamePack(char *buf, size_t sz, const char *name)
154{
64b636b9 155 unsigned int off = 0;
ec7bade0 156 char *copy = xstrdup(name);
fb29421b 157 char *t;
0a8e6ec2 158 /*
159 * NOTE: use of strtok here makes names like foo....com valid.
160 */
fb29421b 161 for (t = strtok(copy, "."); t; t = strtok(NULL, "."))
26ac0430 162 off += rfc1035LabelPack(buf + off, sz - off, t);
ec7bade0 163 xfree(copy);
fb29421b 164 off += rfc1035LabelPack(buf + off, sz - off, NULL);
165 assert(off <= sz);
166 return off;
167}
168
169/*
170 * rfc1035QuestionPack()
26ac0430 171 *
fb29421b 172 * Packs a QUESTION section of a message.
173 * Returns number of octets packed.
174 */
64b636b9 175int
fb29421b 176rfc1035QuestionPack(char *buf,
26ac0430
AJ
177 const size_t sz,
178 const char *name,
179 const unsigned short type,
180 const unsigned short _class)
fb29421b 181{
64b636b9 182 unsigned int off = 0;
fb29421b 183 unsigned short s;
184 off += rfc1035NamePack(buf + off, sz - off, name);
185 s = htons(type);
186 memcpy(buf + off, &s, sizeof(s));
187 off += sizeof(s);
29b8d8d6 188 s = htons(_class);
fb29421b 189 memcpy(buf + off, &s, sizeof(s));
190 off += sizeof(s);
191 assert(off <= sz);
192 return off;
193}
194
195/*
196 * rfc1035HeaderUnpack()
26ac0430 197 *
ec7bade0 198 * Unpacks a RFC1035 message header buffer into the header fields
199 * of the rfc1035_message structure.
0768dfce 200 *
201 * Updates the buffer offset, which is the same as number of
fb29421b 202 * octects unpacked since the header starts at offset 0.
0768dfce 203 *
204 * Returns 0 (success) or 1 (error)
fb29421b 205 */
64b636b9 206int
207rfc1035HeaderUnpack(const char *buf, size_t sz, unsigned int *off, rfc1035_message * h)
fb29421b 208{
209 unsigned short s;
210 unsigned short t;
0768dfce 211 assert(*off == 0);
212 /*
213 * The header is 12 octets. This is a bogus message if the size
214 * is less than that.
215 */
216 if (sz < 12)
26ac0430 217 return 1;
0768dfce 218 memcpy(&s, buf + (*off), sizeof(s));
219 (*off) += sizeof(s);
fb29421b 220 h->id = ntohs(s);
0768dfce 221 memcpy(&s, buf + (*off), sizeof(s));
222 (*off) += sizeof(s);
fb29421b 223 t = ntohs(s);
224 h->qr = (t >> 15) & 0x01;
225 h->opcode = (t >> 11) & 0x0F;
226 h->aa = (t >> 10) & 0x01;
c415c128 227 h->tc = (t >> 9) & 0x01;
fb29421b 228 h->rd = (t >> 8) & 0x01;
229 h->ra = (t >> 7) & 0x01;
0768dfce 230 /*
231 * We might want to check that the reserved 'Z' bits (6-4) are
232 * all zero as per RFC 1035. If not the message should be
233 * rejected.
64b636b9 234 * NO! RFCs say ignore inbound reserved, they may be used in future.
235 * NEW messages need to be set 0, thats all.
0768dfce 236 */
fb29421b 237 h->rcode = t & 0x0F;
0768dfce 238 memcpy(&s, buf + (*off), sizeof(s));
239 (*off) += sizeof(s);
fb29421b 240 h->qdcount = ntohs(s);
0768dfce 241 memcpy(&s, buf + (*off), sizeof(s));
242 (*off) += sizeof(s);
fb29421b 243 h->ancount = ntohs(s);
0768dfce 244 memcpy(&s, buf + (*off), sizeof(s));
245 (*off) += sizeof(s);
fb29421b 246 h->nscount = ntohs(s);
0768dfce 247 memcpy(&s, buf + (*off), sizeof(s));
248 (*off) += sizeof(s);
fb29421b 249 h->arcount = ntohs(s);
0768dfce 250 assert((*off) == 12);
251 return 0;
fb29421b 252}
253
254/*
255 * rfc1035NameUnpack()
26ac0430 256 *
fb29421b 257 * Unpacks a Name in a message buffer into a char*.
258 * Note 'buf' points to the beginning of the whole message,
259 * 'off' points to the spot where the Name begins, and 'sz'
260 * is the size of the whole message. 'name' must be allocated
261 * by the caller.
262 *
263 * Supports the RFC1035 message compression through recursion.
264 *
0768dfce 265 * Updates the new buffer offset.
266 *
267 * Returns 0 (success) or 1 (error)
fb29421b 268 */
0768dfce 269static int
64b636b9 270rfc1035NameUnpack(const char *buf, size_t sz, unsigned int *off, unsigned short *rdlength, char *name, size_t ns, int rdepth)
fb29421b 271{
64b636b9 272 unsigned int no = 0;
fb29421b 273 unsigned char c;
274 size_t len;
275 assert(ns > 0);
276 do {
fd7b53a4
AJ
277 if ((*off) >= sz) {
278 RFC1035_UNPACK_DEBUG;
279 return 1;
280 }
26ac0430
AJ
281 c = *(buf + (*off));
282 if (c > 191) {
64b636b9 283 /* blasted compression */
284 unsigned short s;
285 unsigned int ptr;
286 if (rdepth > 64) { /* infinite pointer loop */
287 RFC1035_UNPACK_DEBUG;
288 return 1;
289 }
26ac0430
AJ
290 memcpy(&s, buf + (*off), sizeof(s));
291 s = ntohs(s);
292 (*off) += sizeof(s);
293 /* Sanity check */
1285d970 294 if ((*off) > sz) {
295 RFC1035_UNPACK_DEBUG;
26ac0430 296 return 1;
1285d970 297 }
26ac0430
AJ
298 ptr = s & 0x3FFF;
299 /* Make sure the pointer is inside this message */
1285d970 300 if (ptr >= sz) {
301 RFC1035_UNPACK_DEBUG;
26ac0430 302 return 1;
1285d970 303 }
26ac0430
AJ
304 return rfc1035NameUnpack(buf, sz, &ptr, rdlength, name + no, ns - no, rdepth + 1);
305 } else if (c > RFC1035_MAXLABELSZ) {
306 /*
307 * "(The 10 and 01 combinations are reserved for future use.)"
308 */
1285d970 309 RFC1035_UNPACK_DEBUG;
26ac0430
AJ
310 return 1;
311 } else {
312 (*off)++;
313 len = (size_t) c;
314 if (len == 0)
315 break;
316 if (len > (ns - no - 1)) { /* label won't fit */
64b636b9 317 RFC1035_UNPACK_DEBUG;
318 return 1;
319 }
26ac0430 320 if ((*off) + len >= sz) { /* message is too short */
64b636b9 321 RFC1035_UNPACK_DEBUG;
322 return 1;
323 }
26ac0430
AJ
324 memcpy(name + no, buf + (*off), len);
325 (*off) += len;
326 no += len;
327 *(name + (no++)) = '.';
328 if (rdlength)
329 *rdlength += len + 1;
330 }
13c900c4 331 } while (c > 0 && no < ns);
4775d711 332 if (no)
26ac0430 333 *(name + no - 1) = '\0';
4775d711 334 else
26ac0430 335 *name = '\0';
0768dfce 336 /* make sure we didn't allow someone to overflow the name buffer */
fb29421b 337 assert(no <= ns);
0768dfce 338 return 0;
fb29421b 339}
340
e210930b
AJ
341/*
342 * rfc1035RRPack()
343 *
344 * Packs a RFC1035 Resource Record into a message buffer from 'RR'.
345 * The caller must allocate and free RR->rdata and RR->name!
346 *
347 * Updates the new message buffer.
348 *
349 * Returns the number of bytes added to the buffer or 0 for error.
350 */
351int
352rfc1035RRPack(char *buf, const size_t sz, const rfc1035_rr * RR)
353{
354 unsigned int off;
355 uint16_t s;
356 uint32_t i;
357
358 off = rfc1035NamePack(buf, sz, RR->name);
359
360 /*
361 * Make sure the remaining message has enough octets for the
362 * rest of the RR fields.
363 */
364 if ((off + sizeof(s)*3 + sizeof(i) + RR->rdlength) > sz) {
365 return 0;
366 }
367 s = htons(RR->type);
368 memcpy(buf + off, &s, sizeof(s));
369 off += sizeof(s);
370 s = htons(RR->_class);
371 memcpy(buf + off, &s, sizeof(s));
372 off += sizeof(s);
373 i = htonl(RR->ttl);
374 memcpy(buf + off, &i, sizeof(i));
375 off += sizeof(i);
376 s = htons(RR->rdlength);
377 memcpy(buf + off, &s, sizeof(s));
378 off += sizeof(s);
379 memcpy(buf + off, &(RR->rdata), RR->rdlength);
380 off += RR->rdlength;
381 assert(off <= sz);
382 return off;
383}
384
fb29421b 385/*
386 * rfc1035RRUnpack()
26ac0430 387 *
fb29421b 388 * Unpacks a RFC1035 Resource Record into 'RR' from a message buffer.
389 * The caller must free RR->rdata!
0768dfce 390 *
391 * Updates the new message buffer offset.
392 *
393 * Returns 0 (success) or 1 (error)
fb29421b 394 */
0768dfce 395static int
64b636b9 396rfc1035RRUnpack(const char *buf, size_t sz, unsigned int *off, rfc1035_rr * RR)
fb29421b 397{
398 unsigned short s;
399 unsigned int i;
c837c655 400 unsigned short rdlength;
64b636b9 401 unsigned int rdata_off;
c837c655 402 if (rfc1035NameUnpack(buf, sz, off, NULL, RR->name, RFC1035_MAXHOSTNAMESZ, 0)) {
26ac0430
AJ
403 RFC1035_UNPACK_DEBUG;
404 memset(RR, '\0', sizeof(*RR));
405 return 1;
0768dfce 406 }
407 /*
408 * Make sure the remaining message has enough octets for the
409 * rest of the RR fields.
410 */
411 if ((*off) + 10 > sz) {
26ac0430
AJ
412 RFC1035_UNPACK_DEBUG;
413 memset(RR, '\0', sizeof(*RR));
414 return 1;
0768dfce 415 }
416 memcpy(&s, buf + (*off), sizeof(s));
417 (*off) += sizeof(s);
fb29421b 418 RR->type = ntohs(s);
0768dfce 419 memcpy(&s, buf + (*off), sizeof(s));
420 (*off) += sizeof(s);
29b8d8d6 421 RR->_class = ntohs(s);
0768dfce 422 memcpy(&i, buf + (*off), sizeof(i));
423 (*off) += sizeof(i);
fb29421b 424 RR->ttl = ntohl(i);
0768dfce 425 memcpy(&s, buf + (*off), sizeof(s));
426 (*off) += sizeof(s);
c837c655 427 rdlength = ntohs(s);
428 if ((*off) + rdlength > sz) {
26ac0430
AJ
429 /*
430 * We got a truncated packet. 'dnscache' truncates UDP
431 * replies at 512 octets, as per RFC 1035.
432 */
433 RFC1035_UNPACK_DEBUG;
434 memset(RR, '\0', sizeof(*RR));
435 return 1;
c415c128 436 }
c837c655 437 RR->rdlength = rdlength;
b8cbc836 438 switch (RR->type) {
3be4d5d1 439#if DNS_CNAME
64b636b9 440 case RFC1035_TYPE_CNAME:
3be4d5d1 441#endif
b8cbc836 442 case RFC1035_TYPE_PTR:
26ac0430
AJ
443 RR->rdata = (char*)xmalloc(RFC1035_MAXHOSTNAMESZ);
444 rdata_off = *off;
445 RR->rdlength = 0; /* Filled in by rfc1035NameUnpack */
446 if (rfc1035NameUnpack(buf, sz, &rdata_off, &RR->rdlength, RR->rdata, RFC1035_MAXHOSTNAMESZ, 0)) {
64b636b9 447 RFC1035_UNPACK_DEBUG;
448 return 1;
449 }
26ac0430
AJ
450 if (rdata_off > ((*off) + rdlength)) {
451 /*
452 * This probably doesn't happen for valid packets, but
453 * I want to make sure that NameUnpack doesn't go beyond
454 * the RDATA area.
455 */
456 RFC1035_UNPACK_DEBUG;
457 xfree(RR->rdata);
458 memset(RR, '\0', sizeof(*RR));
459 return 1;
460 }
461 break;
b8cbc836 462 case RFC1035_TYPE_A:
463 default:
26ac0430
AJ
464 RR->rdata = (char*)xmalloc(rdlength);
465 memcpy(RR->rdata, buf + (*off), rdlength);
466 break;
b8cbc836 467 }
c837c655 468 (*off) += rdlength;
0768dfce 469 assert((*off) <= sz);
470 return 0;
fb29421b 471}
472
42687bb2
HN
473const char *
474rfc1035ErrorMessage(int n)
76cb2b26 475{
42687bb2 476 if (n < 0)
d45671b8 477 n = -n;
42687bb2 478 switch (n) {
76cb2b26 479 case 0:
42687bb2 480 return "No error condition";
26ac0430 481 break;
76cb2b26 482 case 1:
42687bb2 483 return "Format Error: The name server was "
d45671b8 484 "unable to interpret the query.";
26ac0430 485 break;
76cb2b26 486 case 2:
42687bb2 487 return "Server Failure: The name server was "
d45671b8 488 "unable to process this query.";
26ac0430 489 break;
76cb2b26 490 case 3:
42687bb2 491 return "Name Error: The domain name does "
d45671b8 492 "not exist.";
26ac0430 493 break;
76cb2b26 494 case 4:
42687bb2 495 return "Not Implemented: The name server does "
d45671b8 496 "not support the requested kind of query.";
26ac0430 497 break;
76cb2b26 498 case 5:
42687bb2 499 return "Refused: The name server refuses to "
d45671b8 500 "perform the specified operation.";
26ac0430 501 break;
0768dfce 502 case rfc1035_unpack_error:
42687bb2 503 return "The DNS reply message is corrupt or could "
d45671b8 504 "not be safely parsed.";
26ac0430 505 break;
76cb2b26 506 default:
42687bb2 507 return "Unknown Error";
26ac0430 508 break;
76cb2b26 509 }
510}
511
bae9832d 512void
cc192b50 513rfc1035RRDestroy(rfc1035_rr ** rr, int n)
7b724b86 514{
ec6a1b90 515 if (*rr == NULL) {
26ac0430 516 return;
bae9832d 517 }
518
ec6a1b90 519 while (n-- > 0) {
26ac0430
AJ
520 if ((*rr)[n].rdata)
521 xfree((*rr)[n].rdata);
7b724b86 522 }
cc192b50 523 xfree(*rr);
524 *rr = NULL;
7b724b86 525}
526
0768dfce 527/*
ec7bade0 528 * rfc1035QueryUnpack()
26ac0430 529 *
ec7bade0 530 * Unpacks a RFC1035 Query Record into 'query' from a message buffer.
531 *
532 * Updates the new message buffer offset.
533 *
534 * Returns 0 (success) or 1 (error)
535 */
536static int
64b636b9 537rfc1035QueryUnpack(const char *buf, size_t sz, unsigned int *off, rfc1035_query * query)
ec7bade0 538{
539 unsigned short s;
540 if (rfc1035NameUnpack(buf, sz, off, NULL, query->name, RFC1035_MAXHOSTNAMESZ, 0)) {
26ac0430
AJ
541 RFC1035_UNPACK_DEBUG;
542 memset(query, '\0', sizeof(*query));
543 return 1;
ec7bade0 544 }
545 if (*off + 4 > sz) {
26ac0430
AJ
546 RFC1035_UNPACK_DEBUG;
547 memset(query, '\0', sizeof(*query));
548 return 1;
ec7bade0 549 }
550 memcpy(&s, buf + *off, 2);
551 *off += 2;
ec7bade0 552 query->qtype = ntohs(s);
553 memcpy(&s, buf + *off, 2);
554 *off += 2;
9e1f210d 555 query->qclass = ntohs(s);
ec7bade0 556 return 0;
557}
558
fc0f8140 559void
cc192b50 560rfc1035MessageDestroy(rfc1035_message ** msg)
ec7bade0 561{
cc192b50 562 if (!*msg)
26ac0430 563 return;
cc192b50 564 if ((*msg)->query)
26ac0430 565 xfree((*msg)->query);
cc192b50 566 if ((*msg)->answer)
26ac0430 567 rfc1035RRDestroy(&(*msg)->answer, (*msg)->ancount);
cc192b50 568 xfree(*msg);
569 *msg = NULL;
ec7bade0 570}
571
9e1f210d 572/*
573 * rfc1035QueryCompare()
26ac0430 574 *
9e1f210d 575 * Compares two rfc1035_query entries
576 *
577 * Returns 0 (equal) or !=0 (different)
578 */
579int
580rfc1035QueryCompare(const rfc1035_query * a, const rfc1035_query * b)
581{
577090e4 582 size_t la, lb;
9e1f210d 583 if (a->qtype != b->qtype)
26ac0430 584 return 1;
9e1f210d 585 if (a->qclass != b->qclass)
26ac0430 586 return 1;
577090e4 587 la = strlen(a->name);
588 lb = strlen(b->name);
589 if (la != lb) {
26ac0430
AJ
590 /* Trim root label(s) */
591 while (la > 0 && a->name[la - 1] == '.')
592 la--;
593 while (lb > 0 && b->name[lb - 1] == '.')
594 lb--;
577090e4 595 }
596 if (la != lb)
26ac0430 597 return 1;
577090e4 598
599 return strncasecmp(a->name, b->name, la);
9e1f210d 600}
601
ec7bade0 602/*
603 * rfc1035MessageUnpack()
0768dfce 604 *
605 * Takes the contents of a DNS reply and fills in an array
606 * of resource record structures. The records array is allocated
607 * here, and should be freed by calling rfc1035RRDestroy().
608 *
609 * Returns number of records unpacked, zero if DNS reply indicates
610 * zero answers, or an error number < 0.
611 */
612
fb29421b 613int
ec7bade0 614rfc1035MessageUnpack(const char *buf,
26ac0430
AJ
615 size_t sz,
616 rfc1035_message ** answer)
fb29421b 617{
64b636b9 618 unsigned int off = 0;
a99dbd09 619 unsigned int i, j;
64b636b9 620 unsigned int nr = 0;
5457e603 621 rfc1035_message *msg = NULL;
622 rfc1035_rr *recs = NULL;
623 rfc1035_query *querys = NULL;
64b636b9 624 msg = (rfc1035_message*)xcalloc(1, sizeof(*msg));
ec7bade0 625 if (rfc1035HeaderUnpack(buf + off, sz - off, &off, msg)) {
26ac0430 626 RFC1035_UNPACK_DEBUG;
26ac0430
AJ
627 xfree(msg);
628 return -rfc1035_unpack_error;
0768dfce 629 }
64b636b9 630 i = (unsigned int) msg->qdcount;
ec7bade0 631 if (i != 1) {
26ac0430
AJ
632 /* This can not be an answer to our queries.. */
633 RFC1035_UNPACK_DEBUG;
26ac0430
AJ
634 xfree(msg);
635 return -rfc1035_unpack_error;
ec7bade0 636 }
64b636b9 637 querys = msg->query = (rfc1035_query*)xcalloc(i, sizeof(*querys));
a99dbd09 638 for (j = 0; j < i; j++) {
26ac0430
AJ
639 if (rfc1035QueryUnpack(buf, sz, &off, &querys[j])) {
640 RFC1035_UNPACK_DEBUG;
26ac0430
AJ
641 rfc1035MessageDestroy(&msg);
642 return -rfc1035_unpack_error;
643 }
fb29421b 644 }
ec7bade0 645 *answer = msg;
577090e4 646 if (msg->rcode) {
26ac0430 647 RFC1035_UNPACK_DEBUG;
42687bb2 648 return -msg->rcode;
577090e4 649 }
ec7bade0 650 if (msg->ancount == 0)
26ac0430 651 return 0;
64b636b9 652 i = (unsigned int) msg->ancount;
cc192b50 653 recs = msg->answer = (rfc1035_rr*)xcalloc(i, sizeof(*recs));
a99dbd09 654 for (j = 0; j < i; j++) {
26ac0430
AJ
655 if (off >= sz) { /* corrupt packet */
656 RFC1035_UNPACK_DEBUG;
657 break;
658 }
659 if (rfc1035RRUnpack(buf, sz, &off, &recs[j])) { /* corrupt RR */
660 RFC1035_UNPACK_DEBUG;
661 break;
662 }
663 nr++;
fb29421b 664 }
0768dfce 665 if (nr == 0) {
26ac0430
AJ
666 /*
667 * we expected to unpack some answers (ancount != 0), but
668 * didn't actually get any.
669 */
670 rfc1035MessageDestroy(&msg);
671 *answer = NULL;
26ac0430 672 return -rfc1035_unpack_error;
0768dfce 673 }
7b724b86 674 return nr;
fb29421b 675}
676
677/*
b8cbc836 678 * rfc1035BuildAQuery()
26ac0430 679 *
fb29421b 680 * Builds a message buffer with a QUESTION to lookup A records
681 * for a hostname. Caller must allocate 'buf' which should
682 * probably be at least 512 octets. The 'szp' initially
683 * specifies the size of the buffer, on return it contains
684 * the size of the message (i.e. how much to write).
108d67a0 685 * Returns the size of the query
fb29421b 686 */
108d67a0 687ssize_t
e210930b 688rfc1035BuildAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, ssize_t edns_sz)
fb29421b 689{
ec7bade0 690 static rfc1035_message h;
2d72d4fd 691 size_t offset = 0;
fb29421b 692 memset(&h, '\0', sizeof(h));
108d67a0 693 h.id = qid;
fb29421b 694 h.qr = 0;
695 h.rd = 1;
696 h.opcode = 0; /* QUERY */
697 h.qdcount = (unsigned int) 1;
e210930b 698 h.arcount = (edns_sz > 0 ? 1 : 0);
fb29421b 699 offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
700 offset += rfc1035QuestionPack(buf + offset,
26ac0430
AJ
701 sz - offset,
702 hostname,
703 RFC1035_TYPE_A,
704 RFC1035_CLASS_IN);
e210930b
AJ
705 if (edns_sz > 0)
706 offset += rfc2671RROptPack(buf + offset, sz - offset, edns_sz);
9e1f210d 707 if (query) {
26ac0430
AJ
708 query->qtype = RFC1035_TYPE_A;
709 query->qclass = RFC1035_CLASS_IN;
710 xstrncpy(query->name, hostname, sizeof(query->name));
9e1f210d 711 }
fb29421b 712 assert(offset <= sz);
108d67a0 713 return offset;
fb29421b 714}
715
b8cbc836 716/*
717 * rfc1035BuildPTRQuery()
26ac0430 718 *
b8cbc836 719 * Builds a message buffer with a QUESTION to lookup PTR records
720 * for an address. Caller must allocate 'buf' which should
721 * probably be at least 512 octets. The 'szp' initially
722 * specifies the size of the buffer, on return it contains
723 * the size of the message (i.e. how much to write).
fc0f8140 724 * Returns the size of the query
b8cbc836 725 */
108d67a0 726ssize_t
e210930b 727rfc1035BuildPTRQuery(const struct in_addr addr, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, ssize_t edns_sz)
b8cbc836 728{
ec7bade0 729 static rfc1035_message h;
2d72d4fd 730 size_t offset = 0;
b8cbc836 731 static char rev[32];
732 unsigned int i;
733 memset(&h, '\0', sizeof(h));
d0017a72 734 i = (unsigned int) ntohl(addr.s_addr);
735 snprintf(rev, 32, "%u.%u.%u.%u.in-addr.arpa.",
26ac0430
AJ
736 i & 255,
737 (i >> 8) & 255,
738 (i >> 16) & 255,
739 (i >> 24) & 255);
108d67a0 740 h.id = qid;
b8cbc836 741 h.qr = 0;
742 h.rd = 1;
743 h.opcode = 0; /* QUERY */
744 h.qdcount = (unsigned int) 1;
e210930b 745 h.arcount = (edns_sz > 0 ? 1 : 0);
b8cbc836 746 offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
747 offset += rfc1035QuestionPack(buf + offset,
26ac0430
AJ
748 sz - offset,
749 rev,
750 RFC1035_TYPE_PTR,
751 RFC1035_CLASS_IN);
e210930b
AJ
752 if (edns_sz > 0)
753 offset += rfc2671RROptPack(buf + offset, sz - offset, edns_sz);
9e1f210d 754 if (query) {
26ac0430
AJ
755 query->qtype = RFC1035_TYPE_PTR;
756 query->qclass = RFC1035_CLASS_IN;
757 xstrncpy(query->name, rev, sizeof(query->name));
9e1f210d 758 }
b8cbc836 759 assert(offset <= sz);
108d67a0 760 return offset;
b8cbc836 761}
762
558be27a 763/*
764 * We're going to retry a former query, but we
765 * just need a new ID for it. Lucky for us ID
766 * is the first field in the message buffer.
767 */
108d67a0 768void
769rfc1035SetQueryID(char *buf, unsigned short qid)
558be27a 770{
558be27a 771 unsigned short s = htons(qid);
772 memcpy(buf, &s, sizeof(s));
558be27a 773}
774
fb29421b 775#if DRIVER
b8cbc836 776#include <sys/socket.h>
fb29421b 777int
778main(int argc, char *argv[])
779{
e210930b
AJ
780 char input[SQUID_DNS_BUFSZ];
781 char buf[SQUID_DNS_BUFSZ];
782 char rbuf[SQUID_DNS_BUFSZ];
783 size_t sz = SQUID_DNS_BUFSZ;
fb29421b 784 unsigned short sid;
fb29421b 785 int s;
786 int rl;
787 struct sockaddr_in S;
0768dfce 788 if (3 != argc) {
26ac0430
AJ
789 fprintf(stderr, "usage: %s ip port\n", argv[0]);
790 return 1;
0768dfce 791 }
fb29421b 792 setbuf(stdout, NULL);
793 setbuf(stderr, NULL);
794 s = socket(PF_INET, SOCK_DGRAM, 0);
795 if (s < 0) {
26ac0430
AJ
796 perror("socket");
797 return 1;
fb29421b 798 }
0768dfce 799 memset(&S, '\0', sizeof(S));
800 S.sin_family = AF_INET;
801 S.sin_port = htons(atoi(argv[2]));
802 S.sin_addr.s_addr = inet_addr(argv[1]);
e210930b 803 while (fgets(input, RFC1035_DEFAULT_PACKET_SZ, stdin)) {
26ac0430
AJ
804 struct in_addr junk;
805 strtok(input, "\r\n");
e210930b
AJ
806 memset(buf, '\0', RFC1035_DEFAULT_PACKET_SZ);
807 sz = RFC1035_DEFAULT_PACKET_SZ;
26ac0430
AJ
808 if (inet_pton(AF_INET, input, &junk)) {
809 sid = rfc1035BuildPTRQuery(junk, buf, &sz);
810 } else {
811 sid = rfc1035BuildAQuery(input, buf, &sz);
812 }
813 sendto(s, buf, sz, 0, (struct sockaddr *) &S, sizeof(S));
814 do {
815 fd_set R;
816 struct timeval to;
817 FD_ZERO(&R);
818 FD_SET(s, &R);
819 to.tv_sec = 10;
820 to.tv_usec = 0;
821 rl = select(s + 1, &R, NULL, NULL, &to);
822 } while (0);
823 if (rl < 1) {
824 printf("TIMEOUT\n");
825 continue;
826 }
e210930b
AJ
827 memset(rbuf, '\0', RFC1035_DEFAULT_PACKET_SZ);
828 rl = recv(s, rbuf, RFC1035_DEFAULT_PACKET_SZ, 0);
26ac0430
AJ
829 {
830 unsigned short rid = 0;
831 int i;
832 int n;
833 rfc1035_rr *answers = NULL;
834 n = rfc1035AnswersUnpack(rbuf,
835 rl,
836 &answers,
837 &rid);
838 if (n < 0) {
42687bb2 839 printf("ERROR %d\n", -n);
26ac0430
AJ
840 } else if (rid != sid) {
841 printf("ERROR, ID mismatch (%#hx, %#hx)\n", sid, rid);
842 } else {
843 printf("%d answers\n", n);
844 for (i = 0; i < n; i++) {
845 if (answers[i].type == RFC1035_TYPE_A) {
846 struct in_addr a;
2f0b84f7 847 char ipa_str[sizeof(a)];
26ac0430 848 memcpy(&a, answers[i].rdata, 4);
2f0b84f7 849 printf("A\t%d\t%s\n", answers[i].ttl, inet_ntop(AF_INET,&a,tmp,sizeof(a)));
26ac0430
AJ
850 } else if (answers[i].type == RFC1035_TYPE_PTR) {
851 char ptr[128];
852 strncpy(ptr, answers[i].rdata, answers[i].rdlength);
853 printf("PTR\t%d\t%s\n", answers[i].ttl, ptr);
854 } else {
855 fprintf(stderr, "can't print answer type %d\n",
856 (int) answers[i].type);
857 }
858 }
859 }
860 }
fb29421b 861 }
862 return 0;
863}
864#endif