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