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