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